2000-11-02 14:47:47 +00:00
|
|
|
/** Collection of some useful xform helper functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include FORMS_H_LOCATION
|
|
|
|
|
2000-12-29 12:48:02 +00:00
|
|
|
#include <fstream> // ofstream
|
|
|
|
#include <vector>
|
|
|
|
|
2000-11-02 14:47:47 +00:00
|
|
|
#ifdef __GNUG_
|
|
|
|
#pragma implementation
|
|
|
|
#endif
|
2001-03-07 14:25:31 +00:00
|
|
|
|
2001-03-05 19:02:40 +00:00
|
|
|
#include "xforms_helpers.h"
|
2000-11-15 18:02:45 +00:00
|
|
|
#include "lyxlex.h"
|
2001-03-07 14:25:31 +00:00
|
|
|
#include "frontends/FileDialog.h"
|
2000-11-15 18:02:45 +00:00
|
|
|
#include "support/FileInfo.h"
|
|
|
|
#include "support/filetools.h"
|
|
|
|
#include "lyx_gui_misc.h" // WriteAlert
|
|
|
|
#include "gettext.h"
|
2000-11-02 14:47:47 +00:00
|
|
|
|
2000-11-15 18:02:45 +00:00
|
|
|
using std::ofstream;
|
|
|
|
using std::pair;
|
2000-11-02 14:47:47 +00:00
|
|
|
using std::vector;
|
|
|
|
|
2001-03-05 19:02:40 +00:00
|
|
|
// Set an FL_OBJECT to activated or deactivated
|
|
|
|
void setEnabled(FL_OBJECT * ob, bool enable)
|
|
|
|
{
|
|
|
|
if (enable) {
|
|
|
|
fl_activate_object(ob);
|
|
|
|
fl_set_object_lcol(ob, FL_BLACK);
|
|
|
|
} else {
|
|
|
|
fl_deactivate_object(ob);
|
|
|
|
fl_set_object_lcol(ob, FL_INACTIVE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-11-02 14:47:47 +00:00
|
|
|
// Take a string and add breaks so that it fits into a desired label width, w
|
2000-12-29 12:48:02 +00:00
|
|
|
string formatted(string const & sin, int w, int size, int style)
|
2000-11-02 14:47:47 +00:00
|
|
|
{
|
|
|
|
string sout;
|
2000-12-29 12:48:02 +00:00
|
|
|
if (sin.empty()) return sout;
|
2000-11-02 14:47:47 +00:00
|
|
|
|
|
|
|
// break sin up into a vector of individual words
|
|
|
|
vector<string> sentence;
|
|
|
|
string word;
|
2000-11-04 10:00:12 +00:00
|
|
|
for (string::const_iterator sit = sin.begin();
|
|
|
|
sit != sin.end(); ++sit) {
|
|
|
|
if ((*sit) == ' ' || (*sit) == '\n') {
|
2000-11-02 14:47:47 +00:00
|
|
|
sentence.push_back(word);
|
|
|
|
word.erase();
|
|
|
|
} else {
|
|
|
|
word += (*sit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Flush remaining contents of word
|
2000-11-04 10:00:12 +00:00
|
|
|
if (!word.empty() ) sentence.push_back(word);
|
2000-11-02 14:47:47 +00:00
|
|
|
|
|
|
|
string line, l1;
|
2000-11-04 10:00:12 +00:00
|
|
|
for (vector<string>::const_iterator vit = sentence.begin();
|
|
|
|
vit != sentence.end(); ++vit) {
|
|
|
|
if (!l1.empty() ) l1 += ' ';
|
2000-11-02 14:47:47 +00:00
|
|
|
l1 += (*vit);
|
|
|
|
int length = fl_get_string_width(style, size, l1.c_str(),
|
|
|
|
int(l1.length()));
|
2000-11-04 10:00:12 +00:00
|
|
|
if (length >= w) {
|
|
|
|
if (!sout.empty() ) sout += '\n';
|
2000-11-02 14:47:47 +00:00
|
|
|
sout += line;
|
|
|
|
l1 = (*vit);
|
|
|
|
}
|
|
|
|
|
|
|
|
line = l1;
|
|
|
|
}
|
|
|
|
// Flush remaining contents of line
|
2000-11-04 10:00:12 +00:00
|
|
|
if (!line.empty()) {
|
|
|
|
if (!sout.empty() ) sout += '\n';
|
2000-11-02 14:47:47 +00:00
|
|
|
sout += line;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sout;
|
|
|
|
}
|
2000-11-15 18:02:45 +00:00
|
|
|
|
|
|
|
|
2001-03-07 14:25:31 +00:00
|
|
|
string const browseFile(LyXView * lv, string const & filename,
|
2000-12-29 12:48:02 +00:00
|
|
|
string const & title,
|
|
|
|
string const & pattern,
|
|
|
|
pair<string,string> const & dir1,
|
|
|
|
pair<string,string> const & dir2)
|
2000-11-15 18:02:45 +00:00
|
|
|
{
|
|
|
|
string lastPath = ".";
|
2000-12-29 12:48:02 +00:00
|
|
|
if (!filename.empty()) lastPath = OnlyPath(filename);
|
2000-11-15 18:02:45 +00:00
|
|
|
|
2001-03-07 14:25:31 +00:00
|
|
|
FileDialog fileDlg(lv, title, LFUN_SELECT_FILE_SYNC, dir1, dir2);
|
2000-11-15 18:02:45 +00:00
|
|
|
|
2001-03-07 14:25:31 +00:00
|
|
|
FileDialog::Result result;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
result = fileDlg.Select(lastPath, pattern, OnlyFilename(filename));
|
2000-11-15 18:02:45 +00:00
|
|
|
|
2001-03-07 14:25:31 +00:00
|
|
|
if (result.second.empty())
|
|
|
|
return result.second;
|
2000-11-15 18:02:45 +00:00
|
|
|
|
2001-03-07 14:25:31 +00:00
|
|
|
lastPath = OnlyPath(result.second);
|
2000-11-15 18:02:45 +00:00
|
|
|
|
2001-03-07 14:25:31 +00:00
|
|
|
if (result.second.find_first_of("#~$% ") == string::npos)
|
|
|
|
break;
|
|
|
|
|
|
|
|
WriteAlert(_("Filename can't contain any "
|
|
|
|
"of these characters:"),
|
|
|
|
_("space, '#', '~', '$' or '%'."));
|
|
|
|
}
|
2000-11-15 18:02:45 +00:00
|
|
|
|
2001-03-07 14:25:31 +00:00
|
|
|
return result.second;
|
2000-11-15 18:02:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-03-20 01:22:46 +00:00
|
|
|
namespace {
|
|
|
|
|
2000-11-15 18:02:45 +00:00
|
|
|
// sorted by hand to prevent LyXLex from complaining on read().
|
|
|
|
keyword_item xformTags[] = {
|
|
|
|
{ "\\gui_background", FL_COL1 },
|
|
|
|
{ "\\gui_buttonbottom", FL_BOTTOM_BCOL },
|
|
|
|
{ "\\gui_buttonleft", FL_LEFT_BCOL },
|
|
|
|
{ "\\gui_buttonright", FL_RIGHT_BCOL },
|
|
|
|
{ "\\gui_buttontop", FL_TOP_BCOL },
|
|
|
|
{ "\\gui_inactive", FL_INACTIVE },
|
|
|
|
{ "\\gui_push_button", FL_YELLOW },
|
|
|
|
{ "\\gui_selected", FL_MCOL },
|
|
|
|
{ "\\gui_text", FL_BLACK }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2001-03-20 01:22:46 +00:00
|
|
|
const int xformCount = sizeof(xformTags) / sizeof(keyword_item);
|
|
|
|
|
|
|
|
} // namespace anon
|
2000-11-15 18:02:45 +00:00
|
|
|
|
|
|
|
|
2001-03-05 19:02:40 +00:00
|
|
|
bool XformsColor::read(string const & filename)
|
2000-11-15 18:02:45 +00:00
|
|
|
{
|
|
|
|
LyXLex lexrc(xformTags, xformCount);
|
|
|
|
if (!lexrc.setFile(filename))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
while (lexrc.IsOK()) {
|
|
|
|
int const le = lexrc.lex();
|
|
|
|
|
|
|
|
switch (le) {
|
|
|
|
case LyXLex::LEX_UNDEF:
|
|
|
|
lexrc.printError("Unknown tag `$$Token'");
|
|
|
|
continue;
|
|
|
|
case LyXLex::LEX_FEOF:
|
|
|
|
continue;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
RGBColor col;
|
|
|
|
|
|
|
|
if (!lexrc.next()) break;
|
|
|
|
col.r = lexrc.GetInteger();
|
|
|
|
|
|
|
|
if (!lexrc.next()) break;
|
|
|
|
col.g = lexrc.GetInteger();
|
|
|
|
|
|
|
|
if (!lexrc.next()) break;
|
|
|
|
col.b = lexrc.GetInteger();
|
|
|
|
|
|
|
|
fl_mapcolor(le, col.r, col.g, col.b);
|
|
|
|
}
|
2000-11-21 15:46:13 +00:00
|
|
|
|
2000-11-15 18:02:45 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-03-05 19:02:40 +00:00
|
|
|
bool XformsColor::write(string const & filename)
|
2000-11-15 18:02:45 +00:00
|
|
|
{
|
|
|
|
ofstream os(filename.c_str());
|
|
|
|
if (!os)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
os << "### This file is part of\n"
|
|
|
|
<< "### ========================================================\n"
|
|
|
|
<< "### LyX, The Document Processor\n"
|
|
|
|
<< "###\n"
|
|
|
|
<< "### Copyright 1995 Matthias Ettrich\n"
|
|
|
|
<< "### Copyright 1995-2000 The LyX Team.\n"
|
|
|
|
<< "###\n"
|
|
|
|
<< "### ========================================================\n"
|
|
|
|
<< "\n"
|
|
|
|
<< "# This file is written by LyX, if you want to make your own\n"
|
|
|
|
<< "# modifications you should do them from inside LyX and save\n"
|
|
|
|
<< "\n";
|
|
|
|
|
|
|
|
for (int i = 0; i < xformCount; ++i) {
|
|
|
|
string const tag = xformTags[i].tag;
|
|
|
|
int const colorID = xformTags[i].code;
|
|
|
|
RGBColor color;
|
|
|
|
|
|
|
|
fl_getmcolor(colorID, &color.r, &color.g, &color.b);
|
|
|
|
|
|
|
|
os << tag << " "
|
|
|
|
<< color.r << " " << color.g << " " << color.b << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2000-11-21 15:46:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
string RWInfo::error_message;
|
|
|
|
|
|
|
|
bool RWInfo::WriteableDir(string const & name)
|
|
|
|
{
|
|
|
|
error_message.erase();
|
|
|
|
|
|
|
|
if (!AbsolutePath(name)) {
|
|
|
|
error_message = N_("The absolute path is required.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileInfo const tp(name);
|
|
|
|
if (!tp.isDir()) {
|
|
|
|
error_message = N_("Directory does not exist.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tp.writable()) {
|
|
|
|
error_message = N_("Cannot write to this directory.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool RWInfo::ReadableDir(string const & name)
|
|
|
|
{
|
|
|
|
error_message.erase();
|
|
|
|
|
|
|
|
if (!AbsolutePath(name)) {
|
|
|
|
error_message = N_("The absolute path is required.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileInfo const tp(name);
|
|
|
|
if (!tp.isDir()) {
|
|
|
|
error_message = N_("Directory does not exist.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tp.readable()) {
|
|
|
|
error_message = N_("Cannot read this directory.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool RWInfo::WriteableFile(string const & name)
|
|
|
|
{
|
|
|
|
// A writeable file is either:
|
|
|
|
// * An existing file to which we have write access, or
|
|
|
|
// * A file that doesn't yet exist but that would exist in a writeable
|
|
|
|
// directory.
|
|
|
|
|
|
|
|
error_message.erase();
|
|
|
|
|
|
|
|
if (name.empty()) {
|
|
|
|
error_message = N_("No file input.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
string const dir = OnlyPath(name);
|
|
|
|
if (!AbsolutePath(dir)) {
|
|
|
|
error_message = N_("The absolute path is required.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileInfo d(name);
|
|
|
|
if (!d.isDir()) {
|
|
|
|
d.newFile(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d.isDir()) {
|
|
|
|
error_message = N_("Directory does not exist.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d.writable()) {
|
|
|
|
error_message = N_("Cannot write to this directory.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileInfo f(name);
|
|
|
|
if (dir == name || f.isDir()) {
|
|
|
|
error_message = N_("A file is required, not a directory.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f.exist() && !f.writable()) {
|
|
|
|
error_message = N_("Cannot write to this file.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool RWInfo::ReadableFile(string const & name)
|
|
|
|
{
|
|
|
|
error_message.erase();
|
|
|
|
|
|
|
|
if (name.empty()) {
|
|
|
|
error_message = N_("No file input.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
string const dir = OnlyPath(name);
|
|
|
|
if (!AbsolutePath(dir)) {
|
|
|
|
error_message = N_("The absolute path is required.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileInfo d(name);
|
|
|
|
if (!d.isDir()) {
|
|
|
|
d.newFile(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d.isDir()) {
|
|
|
|
error_message = N_("Directory does not exist.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d.readable()) {
|
|
|
|
error_message = N_("Cannot read from this directory.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileInfo f(name);
|
|
|
|
if (dir == name || f.isDir()) {
|
|
|
|
error_message = N_("A file is required, not a directory.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!f.exist()) {
|
|
|
|
error_message = N_("File does not exist.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!f.readable()) {
|
|
|
|
error_message = N_("Cannot read from this file.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|