]> Shamusworld >> Repos - architektonas/blob - src/base/rs_font.cpp
GPL compliance check...
[architektonas] / src / base / rs_font.cpp
1 // rs_font.cpp
2 //
3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
9 //
10 // JLH = James L. Hammons <jlhamm@acm.org>
11 //
12 // Who  When        What
13 // ---  ----------  -----------------------------------------------------------
14 // JLH  05/28/2010  Added this text. :-)
15 //
16
17 #include "rs_font.h"
18
19 #include "rs_color.h"
20 #include "rs_fontchar.h"
21 #include "rs_math.h"
22 #include "rs_system.h"
23
24 /**
25  * Constructor.
26  *
27  * @param owner true if the font owns the letters (blocks). Otherwise
28  *              the letters will be deleted when the font is deleted.
29  */
30 RS_Font::RS_Font(const QString & fn, bool owner): letterList(owner), fileName(fn),
31         encoding(""), loaded(false), letterSpacing(3.0), wordSpacing(6.75),
32         lineSpacingFactor(1.0)
33 {
34 }
35
36 /** @return the fileName of this font. */
37 QString RS_Font::getFileName() const
38 {
39         return fileName;
40 }
41
42 /** @return the encoding of this font. */
43 QString RS_Font::getEncoding() const
44 {
45         return encoding;
46 }
47
48 /** @return the alternative names of this font. */
49 const QStringList & RS_Font::getNames() const
50 {
51         return names;
52 }
53
54 /** @return the author(s) of this font. */
55 const QStringList & RS_Font::getAuthors() const
56 {
57         return authors;
58 }
59
60 /** @return Default letter spacing for this font */
61 double RS_Font::getLetterSpacing()
62 {
63         return letterSpacing;
64 }
65
66 /** @return Default word spacing for this font */
67 double RS_Font::getWordSpacing()
68 {
69         return wordSpacing;
70 }
71
72 /** @return Default line spacing factor for this font */
73 double RS_Font::getLineSpacingFactor()
74 {
75         return lineSpacingFactor;
76 }
77
78 /**
79  * Loads the font into memory.
80  *
81  * @retval true font was already loaded or is loaded now.
82  * @retval false font could not be loaded.
83  */
84 bool RS_Font::loadFont()
85 {
86         RS_DEBUG->print("RS_Font::loadFont");
87
88         if (loaded)
89                 return true;
90
91         QString path;
92
93         // Search for the appropriate font if we have only the name of the font:
94         if (!fileName.toLower().contains(".cxf"))
95         {
96                 QStringList fonts = RS_SYSTEM->getFontList();
97                 QFileInfo file;
98
99                 for(QStringList::Iterator it=fonts.begin(); it!=fonts.end(); it++)
100                 {
101                         if (QFileInfo(*it).baseName().toLower() == fileName.toLower())
102                         {
103                                 path = *it;
104                                 break;
105                         }
106                 }
107         }
108         // We have the full path of the font:
109         else
110                 path = fileName;
111
112         // No font paths found:
113         if (path.isEmpty())
114         {
115                 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Font::loadFont: No fonts available.");
116                 return false;
117         }
118
119         // Open cxf file:
120         QFile file(path);
121
122         if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
123         {
124                 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Font::loadFont: Cannot open font file: %s",
125                         path.toAscii().data());
126                 return false;
127         }
128
129         RS_DEBUG->print("RS_Font::loadFont: Successfully opened font file: %s", path.toAscii().data());
130
131         QTextStream ts(&file);
132
133         // Read line by line until we find a new letter:
134 //I think this is wrong... We're mixing classes here...
135 //AND THAT WAS THE PROBLEM!!!
136 //      while (!file.atEnd())
137         while (!ts.atEnd())
138         {
139                 QString line = ts.readLine();
140
141                 if (line.isEmpty())
142                         continue;
143
144                 // Read font settings:
145                 if (line.at(0) == '#')
146                         ParseIdentifier(ts, line);
147                 // Add another letter to this font:
148                 else if (line.at(0) == '[')
149                         ParseCharacter(ts, line);
150         }
151
152         file.close();
153         loaded = true;
154         RS_DEBUG->print("RS_Font::loadFont OK");
155
156         return true;
157 }
158
159 void RS_Font::ParseIdentifier(QTextStream & ts, QString line)
160 {
161         QStringList list = line.mid(1).split(":");
162         QString identifier = "", value = "";
163
164         if (list.size() >= 1)
165                 identifier = list[0].simplified().toLower();
166
167         if (list.size() >= 2)
168                 value = list[1].simplified();
169
170         if (identifier == "letterspacing")
171                 letterSpacing = value.toDouble();
172         else if (identifier == "wordspacing")
173                 wordSpacing = value.toDouble();
174         else if (identifier == "linespacingfactor")
175                 lineSpacingFactor = value.toDouble();
176         else if (identifier == "author")
177                 authors.append(value);
178         else if (identifier == "name")
179                 names.append(value);
180         else if (identifier == "encoding")
181         {
182                 ts.setCodec(QTextCodec::codecForName(value.toAscii()));
183                 encoding = value;
184         }
185 }
186
187 void RS_Font::ParseCharacter(QTextStream & ts, QString line)
188 {
189         // Unicode character:
190         QChar ch;
191
192         // Read unicode:
193         QRegExp regexp("[0-9A-Fa-f]{4,4}");
194         regexp.indexIn(line);
195         QString cap = regexp.cap();
196
197         if (!cap.isNull())
198         {
199                 int uCode = cap.toInt(NULL, 16);
200                 ch = QChar(uCode);
201         }
202         // Read UTF8 (QCad 1 compatibility)
203         else if (line.indexOf(']') >= 3)
204         {
205                 int i = line.indexOf(']');
206                 QString mid = line.mid(1, i - 1);
207                 ch = QString::fromUtf8(mid.toAscii()).at(0);
208         }
209         // Read normal ascii character:
210         else
211         {
212                 ch = line.at(1);
213         }
214
215         // Create new letter:
216         RS_FontChar * letter = new RS_FontChar(NULL, ch, Vector(0.0, 0.0));
217         // Read entities of this letter:
218         line = ts.readLine();
219
220         while (!line.isEmpty())
221         {
222                 QStringList coords = line.mid(2).split(",");
223                 QStringList::Iterator it2 = coords.begin();
224
225                 if (line.at(0) == 'L')  // Line
226                 {
227                         double x1 = (*it2++).toDouble();
228                         double y1 = (*it2++).toDouble();
229                         double x2 = (*it2++).toDouble();
230                         double y2 = (*it2).toDouble();
231
232                         RS_LineData ld(Vector(x1, y1), Vector(x2, y2));
233                         RS_Line * line = new RS_Line(letter, ld);
234                         line->setPen(RS_Pen(RS2::FlagInvalid));
235                         line->setLayer(NULL);
236                         letter->addEntity(line);
237                 }
238                 else if (line.at(0) == 'A')     // Arc
239                 {
240                         double cx = (*it2++).toDouble();
241                         double cy = (*it2++).toDouble();
242                         double r = (*it2++).toDouble();
243                         double a1 = (*it2++).toDouble() / ARAD;
244                         double a2 = (*it2).toDouble() / ARAD;
245                         bool reversed = (line.at(1) == 'R');
246
247                         RS_ArcData ad(Vector(cx, cy), r, a1, a2, reversed);
248                         RS_Arc * arc = new RS_Arc(letter, ad);
249                         arc->setPen(RS_Pen(RS2::FlagInvalid));
250                         arc->setLayer(NULL);
251                         letter->addEntity(arc);
252                 }
253
254                 line = ts.readLine();
255         }
256
257         letter->calculateBorders();
258         letterList.add(letter);
259 }
260
261 // Wrappers for block list (letters) functions
262 RS_BlockList * RS_Font::getLetterList()
263 {
264         return &letterList;
265 }
266
267 RS_Block * RS_Font::findLetter(const QString & name)
268 {
269         return letterList.find(name);
270 }
271
272 uint RS_Font::countLetters()
273 {
274         return letterList.count();
275 }
276
277 RS_Block * RS_Font::letterAt(uint i)
278 {
279         return letterList.at(i);
280 }
281
282 /**
283  * Dumps the fonts data to stdout.
284  */
285 std::ostream & operator<<(std::ostream & os, const RS_Font & f)
286 {
287     os << " Font file name: " << f.getFileName().toLatin1().data() << "\n";
288     //<< (RS_BlockList&)f << "\n";
289     return os;
290 }