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 // (C) 2010 Underground Software
8 // JLH = James L. Hammons <jlhamm@acm.org>
11 // --- ---------- -----------------------------------------------------------
12 // JLH 05/28/2010 Added this text. :-)
18 #include "rs_fontchar.h"
20 #include "rs_system.h"
25 * @param owner true if the font owns the letters (blocks). Otherwise
26 * the letters will be deleted when the font is deleted.
28 RS_Font::RS_Font(const QString & fn, bool owner): letterList(owner), fileName(fn),
29 encoding(""), loaded(false), letterSpacing(3.0), wordSpacing(6.75),
30 lineSpacingFactor(1.0)
34 /** @return the fileName of this font. */
35 QString RS_Font::getFileName() const
40 /** @return the encoding of this font. */
41 QString RS_Font::getEncoding() const
46 /** @return the alternative names of this font. */
47 const QStringList & RS_Font::getNames() const
52 /** @return the author(s) of this font. */
53 const QStringList & RS_Font::getAuthors() const
58 /** @return Default letter spacing for this font */
59 double RS_Font::getLetterSpacing()
64 /** @return Default word spacing for this font */
65 double RS_Font::getWordSpacing()
70 /** @return Default line spacing factor for this font */
71 double RS_Font::getLineSpacingFactor()
73 return lineSpacingFactor;
77 * Loads the font into memory.
79 * @retval true font was already loaded or is loaded now.
80 * @retval false font could not be loaded.
82 bool RS_Font::loadFont()
84 RS_DEBUG->print("RS_Font::loadFont");
91 // Search for the appropriate font if we have only the name of the font:
92 if (!fileName.toLower().contains(".cxf"))
94 QStringList fonts = RS_SYSTEM->getFontList();
97 for(QStringList::Iterator it=fonts.begin(); it!=fonts.end(); it++)
99 if (QFileInfo(*it).baseName().toLower() == fileName.toLower())
106 // We have the full path of the font:
110 // No font paths found:
113 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Font::loadFont: No fonts available.");
120 if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
122 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Font::loadFont: Cannot open font file: %s",
123 path.toAscii().data());
127 RS_DEBUG->print("RS_Font::loadFont: Successfully opened font file: %s", path.toAscii().data());
129 QTextStream ts(&file);
131 // Read line by line until we find a new letter:
132 //I think this is wrong... We're mixing classes here...
133 //AND THAT WAS THE PROBLEM!!!
134 // while (!file.atEnd())
137 QString line = ts.readLine();
142 // Read font settings:
143 if (line.at(0) == '#')
144 ParseIdentifier(ts, line);
145 // Add another letter to this font:
146 else if (line.at(0) == '[')
147 ParseCharacter(ts, line);
152 RS_DEBUG->print("RS_Font::loadFont OK");
157 void RS_Font::ParseIdentifier(QTextStream & ts, QString line)
159 QStringList list = line.mid(1).split(":");
160 QString identifier = "", value = "";
162 if (list.size() >= 1)
163 identifier = list[0].simplified().toLower();
165 if (list.size() >= 2)
166 value = list[1].simplified();
168 if (identifier == "letterspacing")
169 letterSpacing = value.toDouble();
170 else if (identifier == "wordspacing")
171 wordSpacing = value.toDouble();
172 else if (identifier == "linespacingfactor")
173 lineSpacingFactor = value.toDouble();
174 else if (identifier == "author")
175 authors.append(value);
176 else if (identifier == "name")
178 else if (identifier == "encoding")
180 ts.setCodec(QTextCodec::codecForName(value.toAscii()));
185 void RS_Font::ParseCharacter(QTextStream & ts, QString line)
187 // Unicode character:
191 QRegExp regexp("[0-9A-Fa-f]{4,4}");
192 regexp.indexIn(line);
193 QString cap = regexp.cap();
197 int uCode = cap.toInt(NULL, 16);
200 // Read UTF8 (QCad 1 compatibility)
201 else if (line.indexOf(']') >= 3)
203 int i = line.indexOf(']');
204 QString mid = line.mid(1, i - 1);
205 ch = QString::fromUtf8(mid.toAscii()).at(0);
207 // Read normal ascii character:
213 // Create new letter:
214 RS_FontChar * letter = new RS_FontChar(NULL, ch, Vector(0.0, 0.0));
215 // Read entities of this letter:
216 line = ts.readLine();
218 while (!line.isEmpty())
220 QStringList coords = line.mid(2).split(",");
221 QStringList::Iterator it2 = coords.begin();
223 if (line.at(0) == 'L') // Line
225 double x1 = (*it2++).toDouble();
226 double y1 = (*it2++).toDouble();
227 double x2 = (*it2++).toDouble();
228 double y2 = (*it2).toDouble();
230 RS_LineData ld(Vector(x1, y1), Vector(x2, y2));
231 RS_Line * line = new RS_Line(letter, ld);
232 line->setPen(RS_Pen(RS2::FlagInvalid));
233 line->setLayer(NULL);
234 letter->addEntity(line);
236 else if (line.at(0) == 'A') // Arc
238 double cx = (*it2++).toDouble();
239 double cy = (*it2++).toDouble();
240 double r = (*it2++).toDouble();
241 double a1 = (*it2++).toDouble() / ARAD;
242 double a2 = (*it2).toDouble() / ARAD;
243 bool reversed = (line.at(1) == 'R');
245 RS_ArcData ad(Vector(cx, cy), r, a1, a2, reversed);
246 RS_Arc * arc = new RS_Arc(letter, ad);
247 arc->setPen(RS_Pen(RS2::FlagInvalid));
249 letter->addEntity(arc);
252 line = ts.readLine();
255 letter->calculateBorders();
256 letterList.add(letter);
259 // Wrappers for block list (letters) functions
260 RS_BlockList * RS_Font::getLetterList()
265 RS_Block * RS_Font::findLetter(const QString & name)
267 return letterList.find(name);
270 uint RS_Font::countLetters()
272 return letterList.count();
275 RS_Block * RS_Font::letterAt(uint i)
277 return letterList.at(i);
281 * Dumps the fonts data to stdout.
283 std::ostream & operator<<(std::ostream & os, const RS_Font & f)
285 os << " Font file name: " << f.getFileName().toLatin1().data() << "\n";
286 //<< (RS_BlockList&)f << "\n";