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