kivio

kivio_dia_stencil_spawner.cpp
1/*
2* Kivio - Visual Modelling and Flowcharting
3* Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org>
4*
5* This program is free software; you can redistribute it and/or
6* modify it under the terms of the GNU General Public License
7* as published by the Free Software Foundation; either version 2
8* of the License, or (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program; if not, write to the Free Software
17* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18*/
19
20#include <tqdom.h>
21#include <tqfile.h>
22#include <tqregexp.h>
23#include <tqstringlist.h>
24#include <kdebug.h>
25#include <math.h>
26
27#include "kivio_stencil.h"
28#include "kivio_dia_stencil_spawner.h"
29#include "diapathparser.h"
30
31KivioDiaStencilSpawner::KivioDiaStencilSpawner(KivioStencilSpawnerSet *p) : KivioStencilSpawner(p)
32{
33 m_smlStencilSpawner = new KivioSMLStencilSpawner(p);
34}
35
36KivioDiaStencilSpawner::~KivioDiaStencilSpawner()
37{
38}
39
40TQDomElement KivioDiaStencilSpawner::saveXML(TQDomDocument &d)
41{
42 return m_smlStencilSpawner->saveXML(d);
43}
44
45void KivioDiaStencilSpawner::calculateDimensions(float x, float y)
46{
47 m_xlist.append(x);
48 m_ylist.append(y);
49}
50
51float KivioDiaStencilSpawner::diaPointToKivio(float point, bool xpoint)
52{
53 float returnPoint = 0.0;
54 if(xpoint)
55 {
56 //if(m_lowestx < 0)
57 returnPoint = point - m_lowestx;
58 //else
59 // returnPoint = (fabs(m_highestx) - fabs(m_lowestx)) - (fabs(m_highestx) + fabs(point));
60 }
61 else
62 {
63 //if(m_lowesty < 0)
64 returnPoint =point - m_lowesty;
65 //else
66 // returnPoint = (fabs(m_highesty) + fabs(m_lowesty)) - (fabs(m_highesty) + fabs(point));
67 }
68 //kdDebug () << "Point " << point << " Return point " << returnPoint << endl;
69 return returnPoint;
70}
71
72bool KivioDiaStencilSpawner::load(const TQString &file)
73{
74 TQDomDocument dia("test");
75 TQDomDocument kivio("XML");
76
77 m_filename = file;
78 TQFile f(file);
79
80 if(f.open(IO_ReadOnly) == false)
81 {
82 kdDebug(43000) << "KivioDiaStencilSpawner::load() - Error opening stencil: " << file << endl;
83 return false;
84 }
85 dia.setContent(&f);
86 TQDomNode diaMain = dia.namedItem("shape");
87
88 // Set "creator" attribute
89 TQDomElement firstElement = kivio.createElement("KivioShapeStencil");
90 firstElement.setAttribute("creator", "kiviodiafilter");
91
92 kivio.appendChild(firstElement);
93
94 // Add KivioSMLStencilSpawnerInfo
95 TQDomElement spawnerInfoElement = kivio.createElement("KivioSMLStencilSpawnerInfo");
96 TQDomElement authorInfoElement = kivio.createElement("Author");
97 authorInfoElement.setAttribute("data", "n/a");
98 TQDomElement titleInfoElement = kivio.createElement("Title");
99 titleInfoElement.setAttribute("data", diaMain.namedItem("name").toElement().text());
100 TQDomElement idInfoElement = kivio.createElement("Id");
101 idInfoElement.setAttribute("data", diaMain.namedItem("name").toElement().text());
102 TQDomElement descriptionInfoElement = kivio.createElement("Description");
103 descriptionInfoElement.setAttribute("data", diaMain.namedItem("description").toElement().text());
104 TQDomElement versionInfoElement = kivio.createElement("Version");
105 versionInfoElement.setAttribute("data", "1.0");
106 TQDomElement webInfoElement = kivio.createElement("Web");
107 webInfoElement.setAttribute("data", "http://");
108 TQDomElement emailInfoElement = kivio.createElement("Email");
109 emailInfoElement.setAttribute("data", "n/a");
110 TQDomElement copyrightInfoElement = kivio.createElement("Copyright");
111 copyrightInfoElement.setAttribute("data", "n/a");
112 TQDomElement autoUpdateInfoElement = kivio.createElement("AutoUpdate");
113 autoUpdateInfoElement.setAttribute("data", "off");
114
115 spawnerInfoElement.appendChild(authorInfoElement);
116 spawnerInfoElement.appendChild(titleInfoElement);
117 spawnerInfoElement.appendChild(idInfoElement);
118 spawnerInfoElement.appendChild(descriptionInfoElement);
119 spawnerInfoElement.appendChild(versionInfoElement);
120 spawnerInfoElement.appendChild(webInfoElement);
121 spawnerInfoElement.appendChild(emailInfoElement);
122 spawnerInfoElement.appendChild(copyrightInfoElement);
123 spawnerInfoElement.appendChild(autoUpdateInfoElement);
124
125 kivio.documentElement().appendChild(spawnerInfoElement);
126
127 m_xscale = m_yscale = 20.0f;
128
129 // Add Dimensions
130 TQDomElement dimensionsElement = kivio.createElement("Dimensions");
131 kivio.documentElement().appendChild(dimensionsElement);
132
133 // Calculate Dimensions
134 TQDomElement svgElement = diaMain.namedItem("svg:svg").toElement();
135 TQDomNode svgNode = svgElement.firstChild();
136 while(!svgNode.isNull())
137 {
138 TQDomElement svgChild = svgNode.toElement();
139 if(!svgChild.isNull())
140 {
141 if(svgChild.tagName() == "svg:rect")
142 {
143 // TODO: rx and ry -> rounded rects
144 if(svgChild.hasAttribute("x") && svgChild.hasAttribute("y") && svgChild.hasAttribute("width") && svgChild.hasAttribute("height"))
145 {
146 calculateDimensions(svgChild.attribute("x").toFloat(), svgChild.attribute("y").toFloat());
147 calculateDimensions(svgChild.attribute("x").toFloat() + svgChild.attribute("width").toFloat(), svgChild.attribute("y").toFloat() + svgChild.attribute("height").toFloat());
148 }
149 }
150 else if(svgChild.tagName() == "svg:circle")
151 {
152 if(svgChild.hasAttribute("cx") && svgChild.hasAttribute("cy") && svgChild.hasAttribute("r"))
153 {
154 calculateDimensions((svgChild.attribute("cx").toFloat()) - (svgChild.attribute("r").toFloat()), (svgChild.attribute("cy").toFloat()) - (svgChild.attribute("r").toFloat()));
155 calculateDimensions((svgChild.attribute("cx").toFloat()) + (svgChild.attribute("r").toFloat()), (svgChild.attribute("cy").toFloat()) + (svgChild.attribute("r").toFloat()));
156 }
157 }
158 else if(svgChild.tagName() == "svg:ellipse")
159 {
160 if(svgChild.hasAttribute("cx") && svgChild.hasAttribute("cy") && svgChild.hasAttribute("rx") && svgChild.hasAttribute("ry"))
161 {
162 calculateDimensions((svgChild.attribute("cx").toFloat()) - (svgChild.attribute("rx").toFloat()), (svgChild.attribute("cy").toFloat()) - (svgChild.attribute("ry").toFloat()));
163 calculateDimensions((svgChild.attribute("cx").toFloat()) + (svgChild.attribute("rx").toFloat()), (svgChild.attribute("cy").toFloat()) + (svgChild.attribute("ry").toFloat()));
164 }
165 }
166 else if(svgChild.tagName() == "svg:line")
167 {
168 if(svgChild.hasAttribute("x1") && svgChild.hasAttribute("y1") && svgChild.hasAttribute("x2") && svgChild.hasAttribute("y2"))
169 {
170 calculateDimensions(svgChild.attribute("x1").toFloat(), svgChild.attribute("y1").toFloat());
171 calculateDimensions(svgChild.attribute("x2").toFloat(), svgChild.attribute("y2").toFloat());
172 }
173 }
174 else if(svgChild.tagName() == "svg:polyline")
175 {
176 if(svgChild.hasAttribute("points"))
177 {
178 TQStringList points = TQStringList::split(" ", svgChild.attribute("points"));
179 for(TQStringList::Iterator it = points.begin(); it != points.end(); ++it)
180 {
181 TQString x, y;
182
183 TQStringList parsed = TQStringList::split(",", (*it));
184 TQStringList::Iterator itp = parsed.begin();
185 x = (*itp);
186 ++itp;
187 y = (*itp);
188
189 calculateDimensions(x.toFloat(), y.toFloat());
190 }
191 }
192 }
193 else if(svgChild.tagName() == "svg:polygon")
194 {
195 if(svgChild.hasAttribute("points"))
196 {
197 TQStringList points = TQStringList::split(" ", svgChild.attribute("points"));
198 for(TQStringList::Iterator it = points.begin(); it != points.end(); ++it)
199 {
200 TQString x, y;
201
202 TQStringList parsed = TQStringList::split(",", (*it));
203 TQStringList::Iterator itp = parsed.begin();
204 x = (*itp);
205 ++itp;
206 y = (*itp);
207
208 calculateDimensions(x.toFloat(), y.toFloat());
209 }
210 }
211 }
212 else if(svgChild.tagName() == "svg:path")
213 {
214 if(svgChild.hasAttribute("d"))
215 {
216 DiaPointFinder *dpf = new DiaPointFinder(&m_xlist, &m_ylist);
217 dpf->parseSVG(svgChild.attribute("d"), true);
218 delete dpf;
219 }
220 }
221 }
222 svgNode = svgNode.nextSibling();
223 }
224
225 TQValueList<float>::Iterator itx = m_xlist.begin();
226 TQValueList<float>::Iterator ity = m_ylist.begin();
227 m_highestx = *itx;
228 m_lowestx = *itx;
229 m_highesty = *ity;
230 m_lowesty = *ity;
231 ++itx;
232 ++ity;
233
234 for( ; itx != m_xlist.end(); ++itx)
235 {
236 m_highestx = TQMAX(m_highestx, *itx);
237 m_lowestx = TQMIN(m_lowestx, *itx);
238 }
239
240 for( ; ity != m_ylist.end(); ++ity)
241 {
242 m_highesty = TQMAX(m_highesty, *ity);
243 m_lowesty = TQMIN(m_lowesty, *ity);
244 }
245
246 //if( svgElement.hasAttribute("width") && svgElement.hasAttribute("height"))
247 //{
248 // m_yscale = svgElement.attribute("height").toFloat()/(m_highesty - m_lowesty);
249 // m_xscale = svgElement.attribute("width").toFloat()/(m_highestx - m_lowestx);
250 //}
251 //else
252 {
253 // scale the shape to be close to 30 by 30
254 m_yscale = 30.0/(m_highesty - m_lowesty);
255 m_xscale = 30.0/(m_highestx - m_lowestx);
256 }
257
258 // Add KivioConnectorTarget's
259 TQDomElement connectionsElement = diaMain.namedItem("connections").toElement();
260 TQDomNode connectionsNode = connectionsElement.firstChild();
261 while(!connectionsNode.isNull())
262 {
263 TQDomElement connectionChild = connectionsNode.toElement();
264 if(!connectionChild.isNull())
265 {
266 if(connectionChild.tagName() == "point")
267 {
268 if(connectionChild.hasAttribute("x") && connectionChild.hasAttribute("y"))
269 {
270 TQDomElement kivioConnectorTarget = kivio.createElement("KivioConnectorTarget");
271 kivioConnectorTarget.setAttribute("x", TQString::number(diaPointToKivio(connectionChild.attribute("x").toFloat(),true) * m_xscale));
272 kivioConnectorTarget.setAttribute("y", TQString::number(diaPointToKivio(connectionChild.attribute("y").toFloat(), false) * m_yscale));
273
274 kivio.documentElement().appendChild(kivioConnectorTarget);
275 }
276 }
277 }
278 connectionsNode = connectionsNode.nextSibling();
279 }
280
281 // Add KivioShape's and convert to Kivio's Coordinate System
282 svgNode = svgElement.firstChild();
283 int runs = 0;
284 while(!svgNode.isNull())
285 {
286 TQDomElement svgChild = svgNode.toElement();
287 if(!svgChild.isNull())
288 {
289 if(svgChild.tagName() == "svg:rect")
290 {
291 runs++;
292 // TODO: rx and ry -> rounded rects
293 if(svgChild.hasAttribute("x") && svgChild.hasAttribute("y") && svgChild.hasAttribute("width") && svgChild.hasAttribute("height"))
294 {
295 TQDomElement kivioShape = kivio.createElement("KivioShape");
296 kivioShape.setAttribute("type", "Rectangle");
297 kivioShape.setAttribute("name", TQString::fromLatin1("Element") + TQString::number(runs));
298 kivioShape.setAttribute("x", TQString::number(diaPointToKivio(svgChild.attribute("x").toFloat(),true) * m_xscale));
299 kivioShape.setAttribute("y", TQString::number(diaPointToKivio(svgChild.attribute("y").toFloat(), false) * m_yscale));
300 kivioShape.setAttribute("w", TQString::number(svgChild.attribute("width").toFloat() * m_xscale));
301 kivioShape.setAttribute("h", TQString::number(svgChild.attribute("height").toFloat() * m_yscale));
302 kivio.documentElement().appendChild(kivioShape);
303 }
304 }
305 else if(svgChild.tagName() == "svg:circle")
306 {
307 runs++;
308 if(svgChild.hasAttribute("cx") && svgChild.hasAttribute("cy") && svgChild.hasAttribute("r"))
309 {
310 TQDomElement kivioShape = kivio.createElement("KivioShape");
311 kivioShape.setAttribute("type", "Ellipse");
312 kivioShape.setAttribute("name", TQString::fromLatin1("Element") + TQString::number(runs));
313 kivioShape.setAttribute("x", TQString::number((diaPointToKivio(svgChild.attribute("cx").toFloat() - svgChild.attribute("r").toFloat(),true) * m_xscale)));
314 kivioShape.setAttribute("y", TQString::number((diaPointToKivio(svgChild.attribute("cy").toFloat() - svgChild.attribute("r").toFloat(), false) * m_yscale)));
315 kivioShape.setAttribute("w", TQString::number(svgChild.attribute("r").toFloat() * m_xscale * 2));
316 kivioShape.setAttribute("h", TQString::number(svgChild.attribute("r").toFloat() * m_yscale * 2));
317 kivio.documentElement().appendChild(kivioShape);
318 }
319 }
320 else if(svgChild.tagName() == "svg:ellipse")
321 {
322 runs++;
323 if(svgChild.hasAttribute("cx") && svgChild.hasAttribute("cy") && svgChild.hasAttribute("rx") && svgChild.hasAttribute("ry"))
324 {
325 TQDomElement kivioShape = kivio.createElement("KivioShape");
326 kivioShape.setAttribute("type", "Ellipse");
327 kivioShape.setAttribute("name", TQString::fromLatin1("Element") + TQString::number(runs));
328 kivioShape.setAttribute("x", TQString::number((diaPointToKivio(svgChild.attribute("cx").toFloat() - svgChild.attribute("rx").toFloat(),true) * m_xscale)));
329 kivioShape.setAttribute("y", TQString::number((diaPointToKivio(svgChild.attribute("cy").toFloat() - svgChild.attribute("ry").toFloat(), false) * m_yscale)));
330 kivioShape.setAttribute("w", TQString::number(svgChild.attribute("rx").toFloat() * m_xscale * 2));
331 kivioShape.setAttribute("h", TQString::number(svgChild.attribute("ry").toFloat() * m_yscale * 2));
332 kivio.documentElement().appendChild(kivioShape);
333 }
334 }
335 else if(svgChild.tagName() == "svg:line")
336 {
337 runs++;
338 if(svgChild.hasAttribute("x1") && svgChild.hasAttribute("y1") && svgChild.hasAttribute("x2") && svgChild.hasAttribute("y2"))
339 {
340 TQDomElement kivioShape = kivio.createElement("KivioShape");
341 kivioShape.setAttribute("type", "LineArray");
342 kivioShape.setAttribute("name", TQString::fromLatin1("Element") + TQString::number(runs));
343
344 TQDomElement lineArrayElement = kivio.createElement("Line");
345 lineArrayElement.setAttribute("x1", TQString::number(diaPointToKivio(svgChild.attribute("x1").toFloat(),true) * m_xscale));
346 lineArrayElement.setAttribute("y1", TQString::number(diaPointToKivio(svgChild.attribute("y1").toFloat(), false) * m_yscale));
347 lineArrayElement.setAttribute("x2", TQString::number(diaPointToKivio(svgChild.attribute("x2").toFloat(),true) * m_xscale));
348 lineArrayElement.setAttribute("y2", TQString::number(diaPointToKivio(svgChild.attribute("y2").toFloat(), false) * m_yscale));
349
350 kivioShape.appendChild(lineArrayElement);
351 kivio.documentElement().appendChild(kivioShape);
352 }
353 }
354 else if(svgChild.tagName() == "svg:polyline")
355 {
356 runs++;
357 if(svgChild.hasAttribute("points"))
358 {
359 TQDomElement kivioShape = kivio.createElement("KivioShape");
360 kivioShape.setAttribute("type", "Polyline");
361 kivioShape.setAttribute("name", TQString::fromLatin1("Element") + TQString::number(runs));
362
363 TQStringList points = TQStringList::split(" ", svgChild.attribute("points"));
364 for(TQStringList::Iterator it = points.begin(); it != points.end(); ++it)
365 {
366 TQString x, y;
367
368 TQStringList parsed = TQStringList::split(",", (*it));
369 TQStringList::Iterator itp = parsed.begin();
370 x = (*itp);
371 ++itp;
372 y = (*itp);
373
374 TQDomElement kivioPointElement = kivio.createElement("KivioPoint");
375 kivioPointElement.setAttribute("x", TQString::number(diaPointToKivio(x.toFloat(),true) * m_xscale));
376 kivioPointElement.setAttribute("y", TQString::number(diaPointToKivio(y.toFloat(), false) * m_yscale));
377
378 kivioShape.appendChild(kivioPointElement);
379 }
380 kivio.documentElement().appendChild(kivioShape);
381 }
382 }
383 else if(svgChild.tagName() == "svg:polygon")
384 {
385 runs++;
386 if(svgChild.hasAttribute("points"))
387 {
388 TQDomElement kivioShape = kivio.createElement("KivioShape");
389 kivioShape.setAttribute("type", "Polygon");
390 kivioShape.setAttribute("name", TQString::fromLatin1("Element") + TQString::number(runs));
391
392 TQStringList points = TQStringList::split(" ", svgChild.attribute("points"));
393 for(TQStringList::Iterator it = points.begin(); it != points.end(); ++it)
394 {
395 TQString x, y;
396
397 TQStringList parsed = TQStringList::split(",", (*it));
398 TQStringList::Iterator itp = parsed.begin();
399 x = (*itp);
400 ++itp;
401 y = (*itp);
402
403 TQDomElement kivioPointElement = kivio.createElement("KivioPoint");
404 kivioPointElement.setAttribute("x", TQString::number(diaPointToKivio(x.toFloat(),true) * m_xscale));
405 kivioPointElement.setAttribute("y", TQString::number(diaPointToKivio(y.toFloat(), false) * m_yscale));
406
407 kivioShape.appendChild(kivioPointElement);
408 }
409 kivio.documentElement().appendChild(kivioShape);
410 }
411 }
412 else if(svgChild.tagName() == "svg:path")
413 {
414 runs++;
415 bool isClosed;
416 TQDomElement kivioShape = kivio.createElement("KivioShape");
417 if(svgChild.hasAttribute("d"))
418 {
419
420 if(svgChild.attribute("d").contains('z') || svgChild.attribute("d").contains('Z'))
421 {
422 isClosed = true;
423 kivioShape.setAttribute("type", "ClosedPath");
424 }
425 else
426 {
427 isClosed = false;
428 kivioShape.setAttribute("type", "OpenPath");
429 }
430
431 kivioShape.setAttribute("name", TQString::fromLatin1("Element") + TQString::number(runs));
432
433 DiaPathParser *dpp = new DiaPathParser(&kivio,
434 &kivioShape, m_xscale, m_yscale,
435 m_lowestx, m_lowesty);
436 dpp->parseSVG(svgChild.attribute("d"), true);
437 delete dpp;
438
439
440 }
441
442 if( svgChild.hasAttribute("style"))
443 {
444 // style="stroke: background; stroke-width: 0.8; stroke-miterlimit: 1; stroke-linecap: round; stroke-linejoin: round"
445 // Supported:
446 // stroke-width:
447 // stroke-linejoin: milter, bevel, round
448 // stroke-linecap: round, square, flat
449 // fill: ?
450 TQStringList styles = TQStringList::split(";", svgChild.attribute("style"));
451 for( uint idx = 0; idx < styles.count(); idx++)
452 {
453 //kdDebug(43000) << "Style: " << styles[idx] << endl;
454 if( isClosed && styles[idx].contains("fill:"))
455 {
456 TQDomElement fillStyle = kivio.createElement("KivioFillStyle");
457 if( styles[idx].contains("forground"))
458 fillStyle.setAttribute("color", "#0000");
459 else if (styles[idx].contains("background"))
460 fillStyle.setAttribute("color", "#ffff");
461
462 fillStyle.setAttribute("colorStyle", "1");
463 kivioShape.appendChild(fillStyle);
464 }
465 }
466 }
467 kivio.documentElement().appendChild(kivioShape);
468 }
469 }
470 svgNode = svgNode.nextSibling();
471 }
472
473 // Apply width and height
474
475 dimensionsElement.setAttribute("w", TQString::number((fabs(m_highestx - m_lowestx)) * m_xscale));
476 dimensionsElement.setAttribute("h", TQString::number((fabs(m_highesty - m_lowesty)) * m_yscale));
477
478 m_xlist.clear();
479 m_ylist.clear();
480
481 return loadXML(file, kivio);
482}
483
484bool KivioDiaStencilSpawner::loadXML(const TQString &file, TQDomDocument &d)
485{
486 bool ret = m_smlStencilSpawner->loadXML(file, d);
487
488 m_icon = *m_smlStencilSpawner->icon();
489 m_pSet = m_smlStencilSpawner->set();
490 m_pInfo = m_smlStencilSpawner->info();
491 m_defWidth = m_smlStencilSpawner->defWidth();
492 m_defHeight = m_smlStencilSpawner->defHeight();
493
494 return ret;
495}
496
497KivioStencil *KivioDiaStencilSpawner::newStencil()
498{
499 KivioStencil *newStencil = m_smlStencilSpawner->newStencil();
500 newStencil->setSpawner(this);
501
502 return newStencil;
503}