1 /* webcpp - theme.cpp
2 * Copyright (C)2001-2003 Jeffrey Bakker
3
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 ___________________________________ .. .
18 */
19
20
21 /*
22 Finished
23
24 Asm
25 Asp
26 C
27 C#
28 C++
29 CG
30 Fortran
31 HTML
32 Java
33 Modula*
34 Objective C
35 Pascal
36 Shell
37
38 */
39
40 #include "defsys.h"
41 #include "theme.h"
42 #include <cctype>
43 using namespace std;
44
45 // (de)construction -----------------------------------------------------------
~Theme()46 Theme::~Theme() {
47
48 close();
49 }
Theme()50 Theme::Theme() {
51
52 typical();
53
54 format2 = true;
55 snippet = false;
56 Picture = "\0";
57 } //---------------------------------------------------------------------------
58 // set file -------------------------------------------------------------------
setFile(string filename)59 bool Theme::setFile(string filename) {
60
61 SCSfile = filename;
62
63 if(filename.rfind(".Scs2") == -1) {
64
65 if(filename.rfind(".scs") != -1) {
66 format2 = false;
67 }
68 else
69 filename += ".Scs2";
70 }
71 if( openR(filename) ) {
72
73 return load();
74 } else {
75 // cerr << "...searching default directory.";
76 // search in default webcpp data dir
77 if(filename.rfind(DIRECTORY_SLASH) == -1)
78 {
79 filename = WEBCPP_DATA_DIR + filename;
80
81 if(openR(filename))
82 {
83 return load();
84 }
85 }
86 }
87 return false;
88 }
89 // set background picture -----------------------------------------------------
setPicture(string picture)90 void Theme::setPicture(string picture) {
91
92 Picture = picture;
93 }
94 // get the name of the theme --------------------------------------------------
getThemeName()95 string Theme::getThemeName() {
96
97 string justTheName;
98 int i_dir, i_ext;
99
100 i_dir = SCSfile.rfind(DIRECTORY_SLASH);
101 if(i_dir != -1)
102 {
103 justTheName = SCSfile.substr(i_dir +1);
104 } else {
105 justTheName = SCSfile;
106 }
107 i_ext = justTheName.rfind(".");
108 if(i_ext != -1)
109 {
110 justTheName = justTheName.substr(0,i_ext);
111 }
112
113 return justTheName;
114 }
115 // get background picture -----------------------------------------------------
getImageFile()116 string Theme::getImageFile() {
117
118 return Picture;
119 }
120 // strip pathname from image file for copying ---------------------------------
setImageLeaf()121 void Theme::setImageLeaf() {
122
123 string ImgLeaf, Path;
124
125 int dir_idx = Picture.rfind(DIRECTORY_SLASH);
126
127 if(dir_idx != -1) {
128
129 Path = Picture.substr(0,dir_idx+1);
130 ImgLeaf = Picture.substr(dir_idx+1);
131
132 Picture = ImgLeaf;
133 }
134 }
135 // loading a theme ------------------------------------------------------------
load()136 bool Theme::load() {
137
138 // load an Scs2-format file
139 if(format2) {
140
141 string Scs2buf;
142 CFdatapair ScsXml;
143
144 // check for xml tag
145 getline(ifile,Scs2buf);
146 if(Scs2buf.find("<?xml version=\"1.0\"") == -1)
147 {return false;}
148 // check for the document type
149 getline(ifile,Scs2buf);
150 if(Scs2buf.find("<!DOCTYPE SyntaxColourScheme2") == -1)
151 {return false;}
152 // check for Scs2 data section
153 getline(ifile,Scs2buf);
154 if(Scs2buf.find("<SyntaxColourScheme2>") == -1)
155 {return false;}
156
157 // load the Scs2 data which may be in random order
158 getline(ifile,Scs2buf);
159 while(ifile) {
160
161 // cerr << "\nScs2: " << Scs2buf << endl;
162
163 ScsXml << Scs2buf;
164 ScsVec.push_back(Scs2buf);
165 getline(ifile,Scs2buf);
166 }
167
168 // for(int j=0; j < ScsVec.size(); j++) {
169
170 // cerr << endl << ScsVec[j].info_nv() << endl;
171 // }
172
173 // sort the Scs2 data
174 Colours2[BGCOLOR] = getColour("bgcolor");
175 Colours2[PREPROC] = getColour("preproc");
176 Colours2[NORTEXT] = getColour("nortext");
177 Colours2[SYMBOLS] = getColour("symbols");
178 Colours2[KEYWORD] = getColour("keyword");
179 Colours2[KEYTYPE] = getColour("keytype");
180 Colours2[INTEGER] = getColour("integer");
181 Colours2[FLOATPT] = getColour("floatpt");
182 Colours2[DBLQUOT] = getColour("dblquot");
183 Colours2[SINQUOT] = getColour("sinquot");
184 Colours2[COMMENT] = getColour("comment");
185 // use a background image, if found
186 Picture = getColour("background");
187
188 // check the format of all the colours
189 for(int i=BGCOLOR; i <= COMMENT; i++) {
190
191 if(Colours2[i] == "\0") {
192 typical();
193 return false;
194 }
195
196 if(Colours2[i][0] != '#') {
197 Colours2[i].insert(0,"#");
198 }
199
200 // verify data is in the right format
201 if(!verifyFormat(Colours2[i])) {
202 typical();
203 return false;
204 }
205 // if not, use the defulat scheme
206 }
207 return true;
208 }
209 // load an original SCS-format file
210 for(int i=BGCOLOR; i <= COMMENT; i++) {
211
212 ifile >> Colours2[i];
213
214 // convert old Scs to Scs2 format
215 if(i == NORTEXT) {
216 Colours2[SYMBOLS] = Colours2[NORTEXT];
217 i++;
218 }
219 else
220 if(i == KEYWORD) {
221 Colours2[KEYTYPE] = Colours2[KEYWORD];
222 i++;
223 }
224 else
225 if(i == INTEGER) {
226 Colours2[FLOATPT] = Colours2[INTEGER];
227 i++;
228 }
229 else
230 if(i == DBLQUOT) {
231 Colours2[SINQUOT] = Colours2[DBLQUOT];
232 i++;
233 }
234 // they will look exactly the same as the old style
235
236 if(!verifyFormat(Colours2[i])) {
237 typical();
238 return false;
239 }
240 }
241 return true;
242 }
243
244
getColour(string Name)245 string Theme::getColour(string Name) {
246
247 for(int i=0; i < ScsVec.size(); i++) {
248
249 if(ScsVec[i].getname() == Name)
250 return ScsVec[i].getvalue();
251 }
252 // cerr << "\nScs2: " << Name << " was not found!\n";
253 return "\0";
254 }
255 // write a stylesheet ---------------------------------------------------------
writeCSS(string cssfile)256 bool Theme::writeCSS(string cssfile) {
257
258 if(!openW(cssfile,true)) {return false;}
259 ofile << getCSSdata();
260 closeW();
261 return true;
262 }
263 // set a colour in the theme --------------------------------------------------
setColour(string colour,int num)264 void Theme::setColour(string colour, int num) {
265
266 Colours2[num] = colour;
267 }
268 // set default theme ----------------------------------------------------------
typical()269 void Theme::typical() {
270
271 SCSfile = "typical";
272
273 setColour("#f9f9f9",BGCOLOR);
274 setColour("#a900a9",PREPROC); //a900a9
275 setColour("#000000",NORTEXT);
276 setColour("#0077dd",SYMBOLS);
277 setColour("#224fff",KEYWORD);
278 setColour("#ff9933",KEYTYPE); //224fff //ff9933
279 setColour("#ff0032",INTEGER);
280 setColour("#ff23a6",FLOATPT);
281 setColour("#00b800",DBLQUOT);
282 setColour("#00b86b",SINQUOT);
283 setColour("#666666",COMMENT);
284 }
285 // enforces proper colour format ----------------------------------------------
verifyFormat(string hexData)286 bool Theme::verifyFormat(string hexData) {
287
288 // make sure string is the right length
289 if (hexData.size() != 7) {
290 cerr << hexData << "\a is an invalid colour.\n";
291 return false;
292 }
293
294 // string must start with '#'
295 if (hexData[0] != '#') {
296 cerr << hexData << "\a is an invalid colour.\n";
297 return false;
298 }
299
300 // change string to uppercase
301 for (int i=1; i < 7; i++) {hexData[i] = toupper(hexData[i]);}
302
303 // enforce range from #000000 to #FFFFFF
304 for (int j=1; j < 7; j++) {
305
306 if (hexData[j] < '0' || hexData[j] > 'F') {
307 cerr << hexData << "\a is an invalid colour.\n";
308 return false;
309 }
310 if (ispunct(hexData[j]) || isspace(hexData[j])) {
311 cerr << hexData << "\a is an invalid colour.\n";
312 return false;
313 }
314 }
315
316 return true;
317 } //---------------------------------------------------------------------------
getCSSdata()318 string Theme::getCSSdata() {
319
320 string CSS;
321
322 CSS =
323
324 "/*\nWebcpp v0.8.1 compatible StyleSheet\nhttp://webcpp.sf.net\n"
325 "Theme: " + getThemeName() + "\n*/\n\n" +
326 + ( (snippet) ? "div.webcpp" : "body" ) +
327 "\n{\nbackground-color: " + Colours2[BGCOLOR] +
328 //";\nalign: center;\n"
329 //"color: " + Colours2[COMMENT] + // ";\nborder: solid" +
330 ( (Picture == "\0")
331 ? "\n}\n\n": ";\nbackground-image: url(\"" + Picture +
332 "\");\nbackground-attachment: fixed\n}\n\n" ) +
333
334 ".webcpp a:link {color:" + Colours2[DBLQUOT] + "}\n"
335 ".webcpp a:visited {color:" + Colours2[COMMENT] + "}\n"
336 ".webcpp a:active {color:" + Colours2[KEYWORD] + "}\n"
337 ".webcpp a:hover {color:" + Colours2[PREPROC] + "}\n\n"
338 ".webcpp pre\n{\ncolor: " + Colours2[NORTEXT] + "\n}\n\n"
339 ".webcpp font\n{\nfont-size:100%\n}\n\n"
340 ".webcpp .symbols\n{\ncolor: " + Colours2[SYMBOLS] + "\n}\n\n"
341 ".webcpp .preproc\n{\ncolor: " + Colours2[PREPROC] + "\n}\n\n"
342 ".webcpp .integer\n{\ncolor: " + Colours2[INTEGER] + "\n}\n\n"
343 ".webcpp .floatpt\n{\ncolor: " + Colours2[FLOATPT] + "\n}\n\n"
344 ".webcpp .dblquot\n{\ncolor: " + Colours2[DBLQUOT] + "\n}\n\n"
345 ".webcpp .sinquot\n{\ncolor: " + Colours2[SINQUOT] + "\n}\n\n"
346 ".webcpp .keyword\n{\ncolor: " + Colours2[KEYWORD] + ";\nfont-weight: bold\n}\n\n"
347 ".webcpp .keytype\n{\ncolor: " + Colours2[KEYTYPE] + ";\nfont-weight: bold\n}\n\n"
348 ".webcpp .comment\n{\ncolor: " + Colours2[COMMENT] + ";\nfont-style: italic\n}\n\n";
349
350 return CSS;
351 }
352 //-----------------------------------------------------------------------------
353