Subversion Repositories Scribus

Rev

Rev 18921 | Rev 20477 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4430 cbradney 1
/*
2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
2688 craig 7
 
10223 cbradney 8
#include <QCursor>
13085 jghali 9
#include <QDebug>
9764 jghali 10
#include <QDrag>
10292 cbradney 11
#include <QFile>
12
#include <QList>
9764 jghali 13
#include <QMimeData>
10638 jghali 14
#include <QPainterPath>
10292 cbradney 15
#include <QRegExp>
12795 fschmid 16
#include <QTemporaryFile>
15706 jghali 17
 
10292 cbradney 18
#include "color.h"
3934 cbradney 19
#include "commonstrings.h"
10292 cbradney 20
#include "customfdialog.h"
21
#include "fonts/scfontmetrics.h"
3934 cbradney 22
#include "fpointarray.h"
10292 cbradney 23
#include "loadsaveplugin.h"
3934 cbradney 24
#include "menumanager.h"
10292 cbradney 25
#include "pageitem.h"
26
#include "prefsfile.h"
2834 cbradney 27
#include "prefsmanager.h"
10862 cbradney 28
#include "propertiespalette.h"
10292 cbradney 29
#include "sccolorengine.h"
13460 jghali 30
#include "scclocale.h"
10292 cbradney 31
#include "scconfig.h"
11962 jghali 32
#include "scgzfile.h"
12841 jghali 33
#include "scmimedata.h"
12785 fschmid 34
#include "scpaths.h"
12737 fschmid 35
#include "scpattern.h"
3934 cbradney 36
#include "scraction.h"
10292 cbradney 37
#include "scribus.h"
38
#include "scribusXml.h"
5781 cbradney 39
#include "scribuscore.h"
3207 craig 40
#include "scribusdoc.h"
3934 cbradney 41
#include "selection.h"
10292 cbradney 42
#include "svgplugin.h"
3934 cbradney 43
#include "undomanager.h"
44
#include "util.h"
10292 cbradney 45
#include "util_formats.h"
10200 cbradney 46
#include "util_icon.h"
10203 cbradney 47
#include "util_math.h"
68 Franz 48
 
10862 cbradney 49
 
504 cbradney 50
using namespace std;
51
 
3207 craig 52
int svgimplugin_getPluginAPIVersion()
68 Franz 53
{
3207 craig 54
        return PLUGIN_API_VERSION;
68 Franz 55
}
56
 
3207 craig 57
ScPlugin* svgimplugin_getPlugin()
68 Franz 58
{
3207 craig 59
        SVGImportPlugin* plug = new SVGImportPlugin();
60
        Q_CHECK_PTR(plug);
61
        return plug;
68 Franz 62
}
63
 
3207 craig 64
void svgimplugin_freePlugin(ScPlugin* plugin)
512 fschmid 65
{
3207 craig 66
        SVGImportPlugin* plug = dynamic_cast<SVGImportPlugin*>(plugin);
67
        Q_ASSERT(plug);
68
        delete plug;
512 fschmid 69
}
70
 
3696 craig 71
SVGImportPlugin::SVGImportPlugin() : LoadSavePlugin(),
17117 craig 72
        importAction(new ScrAction(ScrAction::DLL, "", QKeySequence(), this))
1208 cbradney 73
{
3207 craig 74
        // Set action info in languageChange, so we only have to do
3686 craig 75
        // it in one place. This includes registering file format
76
        // support.
3207 craig 77
        languageChange();
5243 cbradney 78
}
12110 fschmid 79
/*
5243 cbradney 80
void SVGImportPlugin::addToMainWindowMenu(ScribusMainWindow *mw)
81
{
3696 craig 82
        importAction->setEnabled(true);
10725 jghali 83
        connect( importAction, SIGNAL(triggered()), SLOT(import()) );
5243 cbradney 84
        mw->scrMenuMgr->addMenuItem(importAction, "FileImport");
1208 cbradney 85
}
12110 fschmid 86
*/
3686 craig 87
SVGImportPlugin::~SVGImportPlugin()
88
{
89
        unregisterAll();
90
};
3207 craig 91
 
92
void SVGImportPlugin::languageChange()
1208 cbradney 93
{
10427 cbradney 94
        importAction->setText( tr("Import &SVG..."));
3686 craig 95
        // (Re)register file format support.
96
        unregisterAll();
97
        registerFormats();
1208 cbradney 98
}
99
 
3207 craig 100
const QString SVGImportPlugin::fullTrName() const
1208 cbradney 101
{
3207 craig 102
        return QObject::tr("SVG Import");
1208 cbradney 103
}
104
 
3207 craig 105
const ScActionPlugin::AboutData* SVGImportPlugin::getAboutData() const
1208 cbradney 106
{
3241 craig 107
        AboutData* about = new AboutData;
3344 fschmid 108
        about->authors = "Franz Schmid <franz@scribus.info>";
3355 cbradney 109
        about->shortDescription = tr("Imports SVG Files");
3357 cbradney 110
        about->description = tr("Imports most SVG files into the current document,\nconverting their vector data into Scribus objects.");
3344 fschmid 111
        about->license = "GPL";
3241 craig 112
        Q_CHECK_PTR(about);
113
        return about;
1208 cbradney 114
}
115
 
3241 craig 116
void SVGImportPlugin::deleteAboutData(const AboutData* about) const
1208 cbradney 117
{
3241 craig 118
        Q_ASSERT(about);
119
        delete about;
1208 cbradney 120
}
121
 
3686 craig 122
void SVGImportPlugin::registerFormats()
3487 craig 123
{
4024 craig 124
        FileFormat fmt(this);
10292 cbradney 125
        fmt.trName = FormatsManager::instance()->nameOfFormat(FormatsManager::SVG);
4024 craig 126
        fmt.formatId = FORMATID_SVGIMPORT;
10292 cbradney 127
        fmt.filter = FormatsManager::instance()->extensionsForFormat(FormatsManager::SVG);
10600 fschmid 128
        fmt.nameMatch = QRegExp("\\."+FormatsManager::instance()->extensionListForFormat(FormatsManager::SVG, 1)+"$", Qt::CaseInsensitive);
3686 craig 129
        fmt.load = true;
130
        fmt.save = false;
10292 cbradney 131
        fmt.mimeTypes = FormatsManager::instance()->mimetypeOfFormat(FormatsManager::SVG);
3643 craig 132
        fmt.priority = 64;
3686 craig 133
        registerFormat(fmt);
3487 craig 134
}
135
 
5642 cbradney 136
bool SVGImportPlugin::fileSupported(QIODevice* /* file */, const QString & fileName) const
3487 craig 137
{
138
        // TODO: identify valid SVG
139
        return true;
140
}
141
 
5539 mrdocs 142
bool SVGImportPlugin::loadFile(const QString & fileName, const FileFormat & /* fmt */, int flags, int /*index*/)
4024 craig 143
{
144
        // For now, "load file" and import are the same thing for this plugin
5539 mrdocs 145
        return import(fileName, flags);
4024 craig 146
}
147
 
5539 mrdocs 148
bool SVGImportPlugin::import(QString filename, int flags)
68 Franz 149
{
5539 mrdocs 150
        if (!checkFlags(flags))
151
                return false;
5781 cbradney 152
        m_Doc=ScCore->primaryMainWindow()->doc;
153
        ScribusMainWindow* mw=(m_Doc==0) ? ScCore->primaryMainWindow() : m_Doc->scMW();
3207 craig 154
        if (filename.isEmpty())
506 fschmid 155
        {
5539 mrdocs 156
                flags |= lfInteractive;
2856 cbradney 157
                PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("SVGPlugin");
506 fschmid 158
                QString wdir = prefs->get("wdir", ".");
10292 cbradney 159
                CustomFDialog diaf(mw, wdir, QObject::tr("Open"), FormatsManager::instance()->fileDialogFormatList(FormatsManager::SVG));
506 fschmid 160
                if (diaf.exec())
161
                {
3207 craig 162
                        filename = diaf.selectedFile();
10427 cbradney 163
                        prefs->set("wdir", filename.left(filename.lastIndexOf("/")));
506 fschmid 164
                }
165
                else
3207 craig 166
                        return true;
415 Franz 167
        }
5781 cbradney 168
 
11576 avox 169
        UndoTransaction* activeTransaction = NULL;
170
        bool emptyDoc = (m_Doc == NULL);
13378 jghali 171
        bool hasCurrentPage = (m_Doc && m_Doc->currentPage());
13371 jghali 172
        TransactionSettings trSettings;
13378 jghali 173
        trSettings.targetName   = hasCurrentPage ? m_Doc->currentPage()->getUName() : "";
13371 jghali 174
        trSettings.targetPixmap = Um::IImageFrame;
175
        trSettings.actionName   = Um::ImportSVG;
176
        trSettings.description  = filename;
177
        trSettings.actionPixmap = Um::ISVG;
178
        if (emptyDoc || !(flags & lfInteractive) || !(flags & lfScripted))
1439 tsoots 179
                UndoManager::instance()->setUndoEnabled(false);
13371 jghali 180
        if (UndoManager::undoEnabled())
181
                activeTransaction = new UndoTransaction(UndoManager::instance()->beginTransaction(trSettings));
8043 jghali 182
        SVGPlug *dia = new SVGPlug(mw, flags);
3207 craig 183
        Q_CHECK_PTR(dia);
13371 jghali 184
        dia->import(filename, trSettings, flags);
11576 avox 185
        if (activeTransaction)
186
        {
187
                activeTransaction->commit();
188
                delete activeTransaction;
189
                activeTransaction = NULL;
190
        }
13371 jghali 191
        if (emptyDoc || !(flags & lfInteractive) || !(flags & lfScripted))
1439 tsoots 192
                UndoManager::instance()->setUndoEnabled(true);
7795 fschmid 193
        if (dia->importCanceled)
3800 subik 194
        {
7795 fschmid 195
                if (dia->importFailed)
196
                        QMessageBox::warning(mw, CommonStrings::trWarning, tr("The file could not be imported"), 1, 0, 0);
197
                else if (dia->unsupported)
198
                        QMessageBox::warning(mw, CommonStrings::trWarning, tr("SVG file contains some unsupported features"), 1, 0, 0);
3800 subik 199
        }
200
 
217 Franz 201
        delete dia;
3207 craig 202
        return true;
68 Franz 203
}
204
 
8043 jghali 205
SVGPlug::SVGPlug( ScribusMainWindow* mw, int flags ) :
5781 cbradney 206
        QObject(mw)
7564 cbradney 207
{      
7578 cbradney 208
        tmpSel=new Selection(this, false);
5781 cbradney 209
        m_Doc=mw->doc;
3800 subik 210
        unsupported = false;
7794 fschmid 211
        importFailed = false;
7795 fschmid 212
        importCanceled = true;
7991 fschmid 213
        importedColors.clear();
12737 fschmid 214
        importedPatterns.clear();
7866 fschmid 215
        docDesc = "";
216
        docTitle = "";
217
        groupLevel = 0;
5539 mrdocs 218
        interactive = (flags & LoadSavePlugin::lfInteractive);
9922 fschmid 219
//      m_gc.setAutoDelete( true );
8043 jghali 220
}
221
 
13371 jghali 222
bool SVGPlug::import(QString fname, const TransactionSettings& trSettings, int flags)
8043 jghali 223
{
224
        if (!loadData(fname))
13403 jghali 225
        {
226
                importFailed = true;
8043 jghali 227
                return false;
13403 jghali 228
        }
10398 cbradney 229
        QString CurDirP = QDir::currentPath();
8043 jghali 230
        QFileInfo efp(fname);
10600 fschmid 231
        QDir::setCurrent(efp.path());
13371 jghali 232
        convert(trSettings, flags);
8043 jghali 233
        QDir::setCurrent(CurDirP);
234
        return true;
235
}
236
 
237
bool SVGPlug::loadData(QString fName)
238
{
239
        QString f("");
11962 jghali 240
        bool isCompressed = false, success = false;
10600 fschmid 241
        QByteArray bb(3, ' ');
8424 fschmid 242
        QFile fi(fName);
8501 cbradney 243
        if (fi.open(QIODevice::ReadOnly))
217 Franz 244
        {
10600 fschmid 245
                fi.read(bb.data(), 2);
8424 fschmid 246
                fi.close();
8625 subik 247
                // Qt4 bb[0]->QChar(bb[0])
248
                if ((QChar(bb[0]) == QChar(0x1F)) && (QChar(bb[1]) == QChar(0x8B)))
8424 fschmid 249
                        isCompressed = true;
250
        }
251
        if ((fName.right(2) == "gz") || (isCompressed))
252
        {
11962 jghali 253
                ScGzFile file(fName);
254
                if (!file.open(QIODevice::ReadOnly))
8043 jghali 255
                        return false;
11962 jghali 256
                success = inpdoc.setContent(&file);
257
                file.close();
217 Franz 258
        }
68 Franz 259
        else
11962 jghali 260
        {
261
                QFile file(fName);
262
                if (!file.open(QIODevice::ReadOnly))
263
                        return false;
264
                success = inpdoc.setContent(&file);
265
                file.close();
266
        }
267
        return success;
68 Franz 268
}
269
 
13371 jghali 270
void SVGPlug::convert(const TransactionSettings& trSettings, int flags)
68 Franz 271
{
272
        bool ret = false;
273
        SvgStyle *gc = new SvgStyle;
274
        QDomElement docElem = inpdoc.documentElement();
20006 jghali 275
        QSizeF wh = parseWidthHeight(docElem);
7573 jghali 276
        double width = wh.width();
277
        double height = wh.height();
5539 mrdocs 278
        if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
217 Franz 279
        {
5781 cbradney 280
                m_Doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false);
281
                m_Doc->addPage(0);
282
                m_Doc->view()->addPage(0);
217 Franz 283
        }
506 fschmid 284
        else
285
        {
5781 cbradney 286
                if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
506 fschmid 287
                {
5798 jghali 288
                        m_Doc=ScCore->primaryMainWindow()->doFileNew(width, height, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
5781 cbradney 289
                        ScCore->primaryMainWindow()->HaveNewDoc();
506 fschmid 290
                        ret = true;
291
                }
292
        }
3207 craig 293
        if ((ret) || (!interactive))
550 fschmid 294
        {
295
                if (width > height)
5781 cbradney 296
                        m_Doc->PageOri = 1;
550 fschmid 297
                else
5781 cbradney 298
                        m_Doc->PageOri = 0;
5789 cbradney 299
                m_Doc->m_pageSize = "Custom";
550 fschmid 300
        }
5781 cbradney 301
        m_Doc->view()->Deselect();
302
        m_Doc->setLoading(true);
303
        m_Doc->DoDrawing = false;
7452 fschmid 304
        m_Doc->view()->updatesOn(false);
14755 jghali 305
        m_Doc->scMW()->setScriptRunning(true);
18921 jghali 306
        qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
10638 jghali 307
        gc->FontFamily = m_Doc->toolSettings.defFont;
5781 cbradney 308
        if (!m_Doc->PageColors.contains("Black"))
309
                m_Doc->PageColors.insert("Black", ScColor(0, 0, 0, 255));
68 Franz 310
        m_gc.push( gc );
1013 fschmid 311
        viewTransformX = 0;
312
        viewTransformY = 0;
313
        viewScaleX = 1;
314
        viewScaleY = 1;
315
        if( !docElem.attribute( "viewBox" ).isEmpty() )
316
        {
317
                QString viewbox( docElem.attribute( "viewBox" ) );
10603 fschmid 318
                QStringList points = viewbox.replace( QRegExp(","), " ").simplified().split( ' ', QString::SkipEmptyParts );
11080 fschmid 319
                if (points.size() > 3)
320
                {
321
                        QMatrix matrix;
20006 jghali 322
                        QSizeF wh2 = parseWidthHeight(docElem);
11080 fschmid 323
                        double w2 = wh2.width();
324
                        double h2 = wh2.height();
325
                        addGraphicContext();
13460 jghali 326
                        viewTransformX = ScCLocale::toDoubleC(points[0]);
327
                        viewTransformY = ScCLocale::toDoubleC(points[1]);
328
                        viewScaleX = w2 / ScCLocale::toDoubleC(points[2]);
329
                        viewScaleY = h2 / ScCLocale::toDoubleC(points[3]);
12101 jghali 330
                        matrix.translate(-viewTransformX * viewScaleX, -viewTransformY * viewScaleY);
11080 fschmid 331
                        matrix.scale(viewScaleX, viewScaleY);
332
                        m_gc.top()->matrix = matrix;
333
                }
1013 fschmid 334
        }
9856 fschmid 335
        QList<PageItem*> Elements = parseGroup( docElem );
7866 fschmid 336
        if (flags & LoadSavePlugin::lfCreateDoc)
337
        {
338
                m_Doc->documentInfo.setTitle(docTitle);
339
                m_Doc->documentInfo.setComments(docDesc);
340
        }
7578 cbradney 341
        tmpSel->clear();
7794 fschmid 342
        if (Elements.count() == 0)
7991 fschmid 343
        {
7794 fschmid 344
                importFailed = true;
7991 fschmid 345
                if (importedColors.count() != 0)
346
                {
8625 subik 347
                        for (int cd = 0; cd < importedColors.count(); cd++)
7991 fschmid 348
                        {
349
                                m_Doc->PageColors.remove(importedColors[cd]);
350
                        }
351
                }
12737 fschmid 352
                if (importedPatterns.count() != 0)
353
                {
354
                        for (int cd = 0; cd < importedPatterns.count(); cd++)
355
                        {
356
                                m_Doc->docPatterns.remove(importedPatterns[cd]);
357
                        }
358
                }
7991 fschmid 359
        }
302 Franz 360
        if (Elements.count() > 1)
217 Franz 361
        {
7445 fschmid 362
                bool isGroup = true;
363
                int firstElem = -1;
364
                if (Elements.at(0)->Groups.count() != 0)
365
                        firstElem = Elements.at(0)->Groups.top();
9856 fschmid 366
                for (int bx = 0; bx < Elements.count(); ++bx)
217 Franz 367
                {
7445 fschmid 368
                        PageItem* bxi = Elements.at(bx);
369
                        if (bxi->Groups.count() != 0)
6605 fschmid 370
                        {
7445 fschmid 371
                                if (bxi->Groups.top() != firstElem)
372
                                        isGroup = false;
373
                        }
374
                        else
375
                                isGroup = false;
376
                }
377
                if (!isGroup)
378
                {
379
                        double minx = 99999.9;
380
                        double miny = 99999.9;
381
                        double maxx = -99999.9;
382
                        double maxy = -99999.9;
383
                        uint lowestItem = 999999;
384
                        uint highestItem = 0;
9856 fschmid 385
                        for (int a = 0; a < Elements.count(); ++a)
7445 fschmid 386
                        {
387
                                Elements.at(a)->Groups.push(m_Doc->GroupCounter);
388
                                PageItem* currItem = Elements.at(a);
8562 jghali 389
                                lowestItem = qMin(lowestItem, currItem->ItemNr);
390
                                highestItem = qMax(highestItem, currItem->ItemNr);
11889 fschmid 391
                                double x1, x2, y1, y2;
12751 fschmid 392
                                currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
11889 fschmid 393
                                minx = qMin(minx, x1);
394
                                miny = qMin(miny, y1);
395
                                maxx = qMax(maxx, x2);
396
                                maxy = qMax(maxy, y2);
6605 fschmid 397
                        }
7445 fschmid 398
                        double gx = minx;
399
                        double gy = miny;
400
                        double gw = maxx - minx;
401
                        double gh = maxy - miny;
402
                        PageItem *high = m_Doc->Items->at(highestItem);
403
                        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, gx, gy, gw, gh, 0, m_Doc->toolSettings.dBrush, m_Doc->toolSettings.dPen, true);
9856 fschmid 404
                        PageItem *neu = m_Doc->Items->takeAt(z);
7445 fschmid 405
                        m_Doc->Items->insert(lowestItem, neu);
406
                        neu->Groups.push(m_Doc->GroupCounter);
407
                        neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
408
                        neu->isGroupControl = true;
409
                        neu->groupsLastItem = high;
9856 fschmid 410
                        for (int a = 0; a < m_Doc->Items->count(); ++a)
6605 fschmid 411
                        {
7445 fschmid 412
                                m_Doc->Items->at(a)->ItemNr = a;
6605 fschmid 413
                        }
7620 fschmid 414
                        neu->setRedrawBounding();
11705 fschmid 415
                        neu->setTextFlowMode(PageItem::TextFlowDisabled);
7445 fschmid 416
                        Elements.prepend(neu);
417
                        m_Doc->GroupCounter++;
217 Franz 418
                }
419
        }
5781 cbradney 420
        m_Doc->DoDrawing = true;
14755 jghali 421
        m_Doc->scMW()->setScriptRunning(false);
3207 craig 422
        if (interactive)
5781 cbradney 423
                m_Doc->setLoading(false);
9380 fschmid 424
        qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
3207 craig 425
        if ((Elements.count() > 0) && (!ret) && (interactive))
217 Franz 426
        {
8262 fschmid 427
                if (flags & LoadSavePlugin::lfScripted)
217 Franz 428
                {
8262 fschmid 429
                        bool loadF = m_Doc->isLoading();
430
                        m_Doc->setLoading(false);
431
                        m_Doc->changed();
432
                        m_Doc->setLoading(loadF);
11835 fschmid 433
                        m_Doc->m_Selection->delaySignalsOn();
9856 fschmid 434
                        for (int dre=0; dre<Elements.count(); ++dre)
8262 fschmid 435
                        {
436
                                m_Doc->m_Selection->addItem(Elements.at(dre), true);
437
                        }
11835 fschmid 438
                        m_Doc->m_Selection->delaySignalsOff();
8262 fschmid 439
                        m_Doc->m_Selection->setGroupRect();
440
                        m_Doc->view()->updatesOn(true);
441
                        importCanceled = false;
217 Franz 442
                }
8262 fschmid 443
                else
444
                {
445
                        m_Doc->DragP = true;
446
                        m_Doc->DraggedElem = 0;
447
                        m_Doc->DragElements.clear();
11835 fschmid 448
                        m_Doc->m_Selection->delaySignalsOn();
9856 fschmid 449
                        for (int dre=0; dre<Elements.count(); ++dre)
8262 fschmid 450
                        {
451
                                m_Doc->DragElements.append(Elements.at(dre)->ItemNr);
452
                                tmpSel->addItem(Elements.at(dre), true);
453
                        }
454
                        ScriXmlDoc *ss = new ScriXmlDoc();
455
                        tmpSel->setGroupRect();
12841 jghali 456
                        ScElemMimeData* md = new ScElemMimeData();
457
                        md->setScribusElem(ss->WriteElem(m_Doc, m_Doc->view(), tmpSel));
12971 jghali 458
                        delete ss;
459
/*#ifndef Q_WS_MAC*/
4302 avox 460
// see #2526
8262 fschmid 461
                        m_Doc->itemSelection_DeleteItem(tmpSel);
12971 jghali 462
/*#endif*/
8262 fschmid 463
                        m_Doc->view()->updatesOn(true);
12737 fschmid 464
                        if (importedColors.count() != 0)
465
                        {
466
                                for (int cd = 0; cd < importedColors.count(); cd++)
467
                                {
468
                                        m_Doc->PageColors.remove(importedColors[cd]);
469
                                }
470
                        }
471
                        if (importedPatterns.count() != 0)
472
                        {
473
                                for (int cd = 0; cd < importedPatterns.count(); cd++)
474
                                {
475
                                        m_Doc->docPatterns.remove(importedPatterns[cd]);
476
                                }
477
                        }
11835 fschmid 478
                        m_Doc->m_Selection->delaySignalsOff();
13371 jghali 479
                        // We must copy the TransationSettings object as it is owned
480
                        // by handleObjectImport method afterwards
481
                        TransactionSettings* transacSettings = new TransactionSettings(trSettings);
482
                        m_Doc->view()->handleObjectImport(md, transacSettings);
8262 fschmid 483
                        m_Doc->DragP = false;
484
                        m_Doc->DraggedElem = 0;
485
                        m_Doc->DragElements.clear();
7991 fschmid 486
                }
217 Franz 487
        }
68 Franz 488
        else
357 Franz 489
        {
7351 fschmid 490
                bool loadF = m_Doc->isLoading();
491
                m_Doc->setLoading(false);
5781 cbradney 492
                m_Doc->changed();
6556 fschmid 493
                m_Doc->reformPages();
7452 fschmid 494
                m_Doc->view()->updatesOn(true);
7351 fschmid 495
                m_Doc->setLoading(loadF);
357 Franz 496
        }
18921 jghali 497
        qApp->restoreOverrideCursor();
68 Franz 498
}
499
 
500
void SVGPlug::addGraphicContext()
501
{
502
        SvgStyle *gc = new SvgStyle;
9922 fschmid 503
        if ( m_gc.top() )
504
                *gc = *( m_gc.top() );
68 Franz 505
        m_gc.push( gc );
506
}
507
 
7612 jghali 508
void SVGPlug::setupNode( const QDomElement &e )
509
{
510
        addGraphicContext();
511
        setupTransform( e );
9922 fschmid 512
        parseStyle(m_gc.top(), e);
7612 jghali 513
}
514
 
68 Franz 515
void SVGPlug::setupTransform( const QDomElement &e )
516
{
9922 fschmid 517
        SvgStyle *gc = m_gc.top();
8501 cbradney 518
        QMatrix mat = parseTransform( e.attribute( "transform" ) );
68 Franz 519
        if (!e.attribute("transform").isEmpty())
520
                gc->matrix = mat * gc->matrix;
521
}
522
 
10785 jghali 523
void SVGPlug::finishNode( const QDomNode &e, PageItem* item)
7612 jghali 524
{
9922 fschmid 525
        SvgStyle *gc = m_gc.top();
8501 cbradney 526
        QMatrix gcm = gc->matrix;
7612 jghali 527
        double BaseX = m_Doc->currentPage()->xOffset();
528
        double BaseY = m_Doc->currentPage()->yOffset();
529
        double coeff1 = sqrt(gcm.m11() * gcm.m11() + gcm.m12() * gcm.m12());
530
        double coeff2 = sqrt(gcm.m21() * gcm.m21() + gcm.m22() * gcm.m22());
531
        switch (item->itemType())
532
        {
533
        case PageItem::ImageFrame:
534
                {
12785 fschmid 535
                        item->ClipEdited = true;
536
                        item->FrameType = 3;
8501 cbradney 537
                        QMatrix mm = gc->matrix;
12785 fschmid 538
                        item->PoLine.map(mm);
7612 jghali 539
                        item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
12785 fschmid 540
                        FPoint wh = getMaxClipF(&item->PoLine);
541
                        item->setWidthHeight(wh.x(), wh.y());
542
                        m_Doc->AdjustItemSize(item);
543
//                      item->moveBy(mm.dx(), mm.dy());
544
//                      item->setWidthHeight(item->width() * mm.m11(), item->height() * mm.m22());
545
//                      item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
13097 subik 546
                        if (item->PictureIsAvailable)
12785 fschmid 547
                        {
548
                                item->setImageXYOffset(0.0, 0.0);
549
                                item->setImageXYScale(item->width() / (item->pixm.width() * (item->pixm.imgInfo.xres / 72.0)),
550
                                                                          item->height() / (item->pixm.height() * (item->pixm.imgInfo.yres / 72.0)));
551
                                item->setImageScalingMode(false, false); // fit to frame
552
                        }
7612 jghali 553
                        break;
554
                }
555
        case PageItem::TextFrame:
556
                {
8501 cbradney 557
                        QMatrix mm = gc->matrix;
7612 jghali 558
                        item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
559
                }
560
                break;
561
        default:
562
                {
563
                        item->ClipEdited = true;
564
                        item->FrameType = 3;
8501 cbradney 565
                        QMatrix mm = gc->matrix;
7612 jghali 566
                        item->PoLine.map(mm);
567
                        /*if (haveViewBox)
568
                        {
10030 cbradney 569
                                QMatrix mv;
7612 jghali 570
                                mv.translate(viewTransformX, viewTransformY);
571
                                mv.scale(viewScaleX, viewScaleY);
572
                                ite->PoLine.map(mv);
573
                        }*/
574
                        item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
575
                        FPoint wh = getMaxClipF(&item->PoLine);
576
                        item->setWidthHeight(wh.x(), wh.y());
7672 fschmid 577
//                      if (item->asPolyLine())
8562 jghali 578
//                              item->setPolyClip(qRound(qMax(item->lineWidth() / 2.0, 1)));
7672 fschmid 579
//                      else
580
//                              item->Clip = FlattenPath(item->PoLine, item->Segments);
12745 fschmid 581
                        FPoint wx = getMinClipF(&item->PoLine);
582
                        inGroupXOrigin = qMin(inGroupXOrigin, wx.x());
583
                        inGroupYOrigin = qMin(inGroupYOrigin, wx.y());
7736 cbradney 584
                        m_Doc->AdjustItemSize(item);
7612 jghali 585
                        break;
586
                }
587
        }
7620 fschmid 588
        item->setRedrawBounding();
7612 jghali 589
        item->OwnPage = m_Doc->OnPage(item);
10785 jghali 590
        if (e.isElement())
591
        {
592
                QString nodeId = e.toElement().attribute("id");
593
                if( !nodeId.isEmpty() )
594
                        item->setItemName(" "+nodeId);
595
        }
7612 jghali 596
        item->setFillTransparency( 1 - gc->FillOpacity * gc->Opacity );
597
        item->setLineTransparency( 1 - gc->StrokeOpacity * gc->Opacity );
598
        item->PLineEnd = gc->PLineEnd;
599
        item->PLineJoin = gc->PLineJoin;
7865 fschmid 600
        if (item->fillColor() == CommonStrings::None)
601
                item->setTextFlowMode(PageItem::TextFlowDisabled);
602
        else
603
                item->setTextFlowMode(PageItem::TextFlowUsesFrameShape);
7678 fschmid 604
        item->DashOffset = gc->dashOffset;
605
        item->DashValues = gc->dashArray;
7612 jghali 606
        if (gc->Gradient != 0)
607
        {
12737 fschmid 608
                if (gc->Gradient == 8)
7612 jghali 609
                {
12737 fschmid 610
                        item->GrType = gc->Gradient;
12745 fschmid 611
                        item->setPattern(importedPattTrans[gc->GCol1]);
612
                        QMatrix mm = gc->matrixg;
12751 fschmid 613
                        double rot = getRotationFromMatrix(mm, 0.0) * 180 / M_PI;
614
                        mm.rotate(rot);
615
                        double patDx = (item->xPos() - BaseX) - mm.dx();
616
                        double patDy = (item->yPos() - BaseY) - mm.dy();
617
                        item->setPatternTransform(mm.m11() * 100.0, mm.m22() * 100.0, patDx, patDy, -rot);
12737 fschmid 618
                }
619
                else
620
                {
621
                        if (gc->GradCo.Stops() > 1)
7612 jghali 622
                        {
12737 fschmid 623
                                item->fill_gradient = gc->GradCo;
624
                                if (!gc->CSpace)
7612 jghali 625
                                {
12737 fschmid 626
                                        item->GrStartX = gc->GX1 * item->width();
627
                                        item->GrStartY = gc->GY1 * item->height();
628
                                        item->GrEndX = gc->GX2 * item->width();
629
                                        item->GrEndY = gc->GY2 * item->height();
630
                                        double angle1 = atan2(gc->GY2-gc->GY1,gc->GX2-gc->GX1)*(180.0/M_PI);
631
                                        double angle2 = atan2(item->GrEndY - item->GrStartX, item->GrEndX - item->GrStartX)*(180.0/M_PI);
632
                                        double dx = item->GrStartX + (item->GrEndX - item->GrStartX) / 2.0;
633
                                        double dy = item->GrStartY + (item->GrEndY - item->GrStartY) / 2.0;
634
                                        QMatrix mm, mm2;
635
                                        if ((gc->GY1 < gc->GY2) && (gc->GX1 < gc->GX2))
636
                                        {
637
                                                mm.rotate(-angle2);
638
                                                mm2.rotate(angle1);
639
                                        }
640
                                        FPointArray gra;
641
                                        gra.setPoints(2, item->GrStartX-dx, item->GrStartY-dy, item->GrEndX-dx, item->GrEndY-dy);
642
                                        gra.map(mm*mm2);
643
                                        gra.translate(dx, dy);
644
                                        item->GrStartX = gra.point(0).x();
645
                                        item->GrStartY = gra.point(0).y();
646
                                        item->GrEndX = gra.point(1).x();
647
                                        item->GrEndY = gra.point(1).y();
7612 jghali 648
                                }
12737 fschmid 649
                                else
650
                                {
651
                                        QMatrix mm = gc->matrix;
652
                                        mm = gc->matrixg * mm;
653
                                        FPointArray gra;
654
                                        gra.setPoints(2, gc->GX1, gc->GY1, gc->GX2, gc->GY2);
655
                                        gra.map(mm);
656
                                        gc->GX1 = gra.point(0).x();
657
                                        gc->GY1 = gra.point(0).y();
658
                                        gc->GX2 = gra.point(1).x();
659
                                        gc->GY2 = gra.point(1).y();
660
                                        item->GrStartX = gc->GX1 - item->xPos() + BaseX;
661
                                        item->GrStartY = gc->GY1 - item->yPos() + BaseY;
662
                                        item->GrEndX = gc->GX2 - item->xPos() + BaseX;
663
                                        item->GrEndY = gc->GY2 - item->yPos() + BaseY;
664
                                }
665
                                item->GrType = gc->Gradient;
7612 jghali 666
                        }
667
                        else
668
                        {
12737 fschmid 669
                                item->GrType = 0;
670
                                QList<VColorStop*> cstops = gc->GradCo.colorStops();
671
                                item->setFillColor(cstops.at(0)->name);
672
                                item->setFillShade(cstops.at(0)->shade);
7612 jghali 673
                        }
674
                }
675
        }
676
}
677
 
7605 jghali 678
bool SVGPlug::isIgnorableNode( const QDomElement &e )
679
{
680
        QString nodeName(e.tagName());
10021 jghali 681
        return isIgnorableNodeName(nodeName);
682
}
683
 
684
bool SVGPlug::isIgnorableNodeName( const QString &n )
685
{
686
        if (n.startsWith("sodipodi") || n.startsWith("inkscape") || n == "metadata")
7605 jghali 687
                return true;
688
        return false;
689
}
690
 
12725 jghali 691
FPoint SVGPlug::parseTextPosition(const QDomElement &e, const FPoint* pos)
8230 jghali 692
{
12725 jghali 693
        // FIXME According to spec, we should in fact return a point list
694
        double  x = pos ? pos->x() : 0.0;
695
        double  y = pos ? pos->y() : 0.0;
696
 
697
        if (e.hasAttribute( "x" ))
8230 jghali 698
        {
12725 jghali 699
                QString xatt =  e.attribute( "x" , "0" );
700
                if ( xatt.contains(',') || xatt.contains(' ') )
701
                {
702
                        xatt.replace(QChar(','), QChar(' '));
703
                        QStringList xl(xatt.split(QChar(' '), QString::SkipEmptyParts));
704
                        xatt = xl.first();
705
                }
706
                x = parseUnit( xatt );
8230 jghali 707
        }
12725 jghali 708
 
709
        if (e.hasAttribute( "y" ))
8230 jghali 710
        {
12725 jghali 711
                QString yatt =  e.attribute( "y" , "0" );
712
                if ( yatt.contains(',') || yatt.contains(' ') )
713
                {
714
                        yatt.replace(QChar(','), QChar(' '));
715
                        QStringList yl(yatt.split(QChar(' '), QString::SkipEmptyParts));
716
                        yatt = yl.first();
717
                }
718
                y = parseUnit( yatt );
8230 jghali 719
        }
12725 jghali 720
 
721
        if (e.hasAttribute( "dx" ))
722
        {
723
                QString dxatt =  e.attribute( "dx" , "0" );
724
                if ( dxatt.contains(',') || dxatt.contains(' ') )
725
                {
726
                        dxatt.replace(QChar(','), QChar(' '));
727
                        QStringList xl(dxatt.split(QChar(' '), QString::SkipEmptyParts));
728
                        dxatt = xl.first();
729
                }
730
                x += parseUnit( dxatt );
731
        }
732
 
733
        if (e.hasAttribute( "dy" ))
734
        {
735
                QString dyatt =  e.attribute( "dy" , "0" );
736
                if ( dyatt.contains(',') || dyatt.contains(' ') )
737
                {
738
                        dyatt.replace(QChar(','), QChar(' '));
739
                        QStringList xl(dyatt.split(QChar(' '), QString::SkipEmptyParts));
740
                        dyatt = xl.first();
741
                }
742
                y += parseUnit( dyatt );
743
        }
744
 
8230 jghali 745
        return FPoint(x, y);
746
}
747
 
20006 jghali 748
QSizeF SVGPlug::parseWidthHeight(const QDomElement &e)
7573 jghali 749
{
20006 jghali 750
        QSizeF size(550, 841);
7573 jghali 751
        QString sw = e.attribute("width", "100%");
752
        QString sh = e.attribute("height", "100%");
753
        double w =  550, h = 841;
754
        if (!sw.isEmpty())
755
                w = sw.endsWith("%") ? fromPercentage(sw) : parseUnit(sw);
756
        if (!sh.isEmpty())
757
                h = sh.endsWith("%") ? fromPercentage(sh) : parseUnit(sh);
758
        if (!e.attribute("viewBox").isEmpty())
759
        {
20006 jghali 760
                QRectF viewBox = parseViewBox(e);
7573 jghali 761
                double scw = (viewBox.width() > 0 && viewBox.height() > 0) ? viewBox.width()  : size.width();
762
                double sch = (viewBox.width() > 0 && viewBox.height() > 0) ? viewBox.height() : size.height();
763
                w *= (sw.endsWith("%") ? scw : 1.0);
764
                h *= (sh.endsWith("%") ? sch : 1.0);
765
        }
766
        else
767
        {
768
                w *= (sw.endsWith("%") ? size.width() : 1.0);
769
                h *= (sh.endsWith("%") ? size.height() : 1.0);
770
        }
8230 jghali 771
        // OpenOffice files may not have width and height attributes, so avoid unnecessary large dimensions
772
        if (w > 10000 || h > 10000)
773
        {
774
                double m = max(w, h);
775
                w = w / m * 842;
776
                h = h / m * 842;
777
        }
20006 jghali 778
        size.setWidth(w);
779
        size.setHeight(h);
7573 jghali 780
        return size;
781
}
782
 
20006 jghali 783
QRectF SVGPlug::parseViewBox(const QDomElement &e)
7573 jghali 784
{
20006 jghali 785
        QRectF box(0, 0, 0, 0);
7573 jghali 786
        if ( !e.attribute( "viewBox" ).isEmpty() )
787
        {
788
                QString viewbox( e.attribute( "viewBox" ) );
10603 fschmid 789
                QStringList points = viewbox.replace( QRegExp(","), " ").simplified().split( ' ', QString::SkipEmptyParts );
11080 fschmid 790
                if (points.size() > 3)
791
                {
13460 jghali 792
                        double left   = ScCLocale::toDoubleC(points[0]);
793
                        double bottom = ScCLocale::toDoubleC(points[1]);
794
                        double width  = ScCLocale::toDoubleC(points[2]);
795
                        double height = ScCLocale::toDoubleC(points[3]);
11080 fschmid 796
                        box.setCoords((int) left, (int) bottom, (int) (left + width), (int) (bottom + height));
797
                }
7573 jghali 798
        }
799
        return box;
800
}
801
 
7556 jghali 802
void SVGPlug::parseDefs(const QDomElement &e)
803
{
804
        for ( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
805
        {
806
                QDomElement b = n.toElement();
7612 jghali 807
                if ( b.isNull() )
7556 jghali 808
                        continue;
809
                SvgStyle svgStyle;
810
                parseStyle( &svgStyle, b );
7605 jghali 811
                if ( !svgStyle.Display)
7556 jghali 812
                        continue;
16887 jghali 813
                QString STag2 = parseTagName(b);
814
                if (STag2 == "g" )
10854 jghali 815
                {
816
                        QString id = b.attribute("id", "");
817
                        if (!id.isEmpty())
818
                                m_nodeMap.insert(id, b);
8507 jghali 819
                        parseDefs(b);
10854 jghali 820
                }
16887 jghali 821
                else if (STag2 == "linearGradient" || STag2 == "radialGradient")
7556 jghali 822
                        parseGradient( b );
7607 fschmid 823
                else if (STag2 == "clipPath")
824
                        parseClipPath(b);
12737 fschmid 825
                else if (STag2 == "pattern")
826
                        parsePattern(b);
7556 jghali 827
                else if ( b.hasAttribute("id") )
828
                {
829
                        QString id = b.attribute("id");
830
                        if (!id.isEmpty())
831
                                m_nodeMap.insert(id, b);
832
                }
833
        }
834
}
835
 
7605 jghali 836
void SVGPlug::parseClipPath(const QDomElement &e)
837
{
838
        QString id(e.attribute("id"));
839
        if (!id.isEmpty())
840
        {
841
                FPointArray clip;
842
                QDomNode n2 = e.firstChild();
843
                QDomElement b2 = n2.toElement();
844
                while (b2.nodeName() == "use")
8604 jghali 845
                        b2 = getReferencedNode(b2);
7607 fschmid 846
                if (b2.nodeName() == "path")
847
                        parseSVG( b2.attribute( "d" ), &clip );
848
                else if (b2.nodeName() == "rect")
849
                {
12101 jghali 850
                        double x = parseUnit( b2.attribute( "x", "0.0" ));
851
                        double y = parseUnit( b2.attribute( "y", "0.0" ));
852
                        double width  = parseUnit( b2.attribute( "width" ));
7607 fschmid 853
                        double height = parseUnit( b2.attribute( "height" ) );
12101 jghali 854
                        clip.addQuadPoint(x, y, x, y, width+x, y, width+x, y);
855
                        clip.addQuadPoint(width+x, y, width+x, y, width+x, height+y, width+x, height+y);
856
                        clip.addQuadPoint(width+x, height+y, width+x, height+y, x, height+y, x, height+y);
857
                        clip.addQuadPoint(x, height+y, x, height+y, x, y, x, y);
7607 fschmid 858
                }
17343 jghali 859
                if (b2.hasAttribute("transform"))
860
                {
861
                        QMatrix transform = parseTransform(b2.attribute("transform"));
862
                        clip.map(transform);
863
                }
7605 jghali 864
                if (clip.size() >= 2)
865
                        m_clipPaths.insert(id, clip);
866
        }
867
}
868
 
869
void SVGPlug::parseClipPathAttr(const QDomElement &e, FPointArray& clipPath)
870
{
871
        clipPath.resize(0);
12802 fschmid 872
/*      if (e.hasAttribute("style"))
12785 fschmid 873
        {
874
                QString style = e.attribute( "style" ).simplified();
875
                QStringList substyles = style.split(';', QString::SkipEmptyParts);
876
                for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
877
                {
878
                        QStringList substyle = (*it).split(':', QString::SkipEmptyParts);
879
                        QString command(substyle[0].trimmed());
880
                        QString params(substyle[1].trimmed());
881
                        if (command == "clip-path")
882
                        {
883
                                if (params.startsWith( "url("))
884
                                {
885
                                        unsigned int start = params.indexOf("#") + 1;
886
                                        unsigned int end = params.lastIndexOf(")");
887
                                        QString key = params.mid(start, end - start);
888
                                        QMap<QString, FPointArray>::iterator it = m_clipPaths.find(key);
889
                                        if (it != m_clipPaths.end())
890
                                                clipPath = it.value().copy();
891
                                }
892
                        }
893
                }
12802 fschmid 894
        } */
7605 jghali 895
        if (e.hasAttribute("clip-path"))
896
        {
897
                QString attr = e.attribute("clip-path");
898
                if (attr.startsWith( "url("))
899
                {
10517 cbradney 900
                        unsigned int start = attr.indexOf("#") + 1;
10427 cbradney 901
                        unsigned int end = attr.lastIndexOf(")");
7605 jghali 902
                        QString key = attr.mid(start, end - start);
903
                        QMap<QString, FPointArray>::iterator it = m_clipPaths.find(key);
904
                        if (it != m_clipPaths.end())
10516 cbradney 905
                                clipPath = it.value().copy();
7605 jghali 906
                }
907
        }
908
}
909
 
15171 jghali 910
QList<PageItem*> SVGPlug::parseA(const QDomElement &e)
911
{
912
        QList<PageItem*> aElements;
913
        for ( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
914
        {
915
                QDomElement b = n.toElement();
916
                if( b.isNull() || isIgnorableNode(b) )
917
                        continue;
918
                SvgStyle svgStyle;
919
                parseStyle( &svgStyle, b);
920
                if (!svgStyle.Display)
921
                        continue;
922
                QList<PageItem*> el = parseElement(b);
923
                for (int ec = 0; ec < el.count(); ++ec)
924
                        aElements.append(el.at(ec));
925
        }
926
        return aElements;
927
}
928
 
9856 fschmid 929
QList<PageItem*> SVGPlug::parseGroup(const QDomElement &e)
68 Franz 930
{
7612 jghali 931
        FPointArray clipPath;
9856 fschmid 932
        QList<PageItem*> GElements, gElements;
7612 jghali 933
        double BaseX = m_Doc->currentPage()->xOffset();
934
        double BaseY = m_Doc->currentPage()->yOffset();
7866 fschmid 935
        groupLevel++;
7612 jghali 936
        setupNode(e);
937
        parseClipPathAttr(e, clipPath);
7640 fschmid 938
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, 1, 1, 0, CommonStrings::None, CommonStrings::None, true);
7612 jghali 939
        PageItem *neu = m_Doc->Items->at(z);
7315 jghali 940
        for ( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
217 Franz 941
        {
68 Franz 942
                QDomElement b = n.toElement();
7612 jghali 943
                if( b.isNull() || isIgnorableNode(b) )
68 Franz 944
                        continue;
6356 jghali 945
                SvgStyle svgStyle;
12785 fschmid 946
                parseStyle( &svgStyle, b);
6356 jghali 947
                if (!svgStyle.Display)
7612 jghali 948
                        continue;
9856 fschmid 949
                QList<PageItem*> el = parseElement(b);
950
                for (int ec = 0; ec < el.count(); ++ec)
7612 jghali 951
                        gElements.append(el.at(ec));
7315 jghali 952
        }
7866 fschmid 953
        groupLevel--;
9922 fschmid 954
        SvgStyle *gc = m_gc.top();
12802 fschmid 955
        if (clipPath.size() == 0)
956
        {
957
                if (gc->clipPath.size() != 0)
958
                        clipPath = gc->clipPath.copy();
959
        }
10854 jghali 960
        if (gElements.count() == 0 || (gElements.count() < 2 && (clipPath.size() == 0) && (gc->Opacity == 1.0)))
7612 jghali 961
        {
13356 jghali 962
                // Unfortunately we have to take the long route here, or we risk crash on undo/redo
963
                // FIXME : create group object after parsing grouped objects
964
                /*m_Doc->Items->takeAt(z);
965
                delete neu;*/
966
                Selection tmpSelection(m_Doc, false);
967
                tmpSelection.addItem(neu);
968
                m_Doc->itemSelection_DeleteItem(&tmpSelection);
9856 fschmid 969
                for (int a = 0; a < m_Doc->Items->count(); ++a)
7640 fschmid 970
                {
971
                        m_Doc->Items->at(a)->ItemNr = a;
972
                }
9856 fschmid 973
                for (int gr = 0; gr < gElements.count(); ++gr)
7640 fschmid 974
                {
975
                        GElements.append(gElements.at(gr));
976
                }
7612 jghali 977
        }
978
        else
979
        {
980
                double minx = 99999.9;
981
                double miny = 99999.9;
982
                double maxx = -99999.9;
983
                double maxy = -99999.9;
984
                GElements.append(neu);
9856 fschmid 985
                for (int gr = 0; gr < gElements.count(); ++gr)
7612 jghali 986
                {
987
                        PageItem* currItem = gElements.at(gr);
11889 fschmid 988
                        double x1, x2, y1, y2;
12751 fschmid 989
                        currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
11889 fschmid 990
                        minx = qMin(minx, x1);
991
                        miny = qMin(miny, y1);
992
                        maxx = qMax(maxx, x2);
993
                        maxy = qMax(maxy, y2);
7612 jghali 994
                }
995
                double gx = minx;
996
                double gy = miny;
997
                double gw = maxx - minx;
998
                double gh = maxy - miny;
999
                neu->setXYPos(gx, gy);
1000
                neu->setWidthHeight(gw, gh);
1001
                if (clipPath.size() != 0)
1002
                {
10396 jghali 1003
                        QMatrix mm = gc->matrix;
7612 jghali 1004
                        neu->PoLine = clipPath.copy();
1005
                        neu->PoLine.map(mm);
12101 jghali 1006
                        neu->PoLine.translate(-gx + BaseX, -gy + BaseY);
7612 jghali 1007
                        clipPath.resize(0);
13356 jghali 1008
 
7612 jghali 1009
                }
1010
                else
1011
                        neu->SetRectFrame();
1012
                neu->Clip = FlattenPath(neu->PoLine, neu->Segments);
1013
                neu->Groups.push(m_Doc->GroupCounter);
1014
                neu->isGroupControl = true;
17294 jghali 1015
                neu->groupsLastItem = gElements.last();
7612 jghali 1016
                if( !e.attribute("id").isEmpty() )
1017
                        neu->setItemName(e.attribute("id"));
1018
                else
1019
                        neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
1020
                neu->setFillTransparency(1 - gc->Opacity);
12745 fschmid 1021
                neu->gXpos = neu->xPos() - gx;
1022
                neu->gYpos = neu->yPos() - gy;
1023
                neu->gWidth = gw;
1024
                neu->gHeight = gh;
9856 fschmid 1025
                for (int gr = 0; gr < gElements.count(); ++gr)
7612 jghali 1026
                {
1027
                        gElements.at(gr)->Groups.push(m_Doc->GroupCounter);
12745 fschmid 1028
                        gElements.at(gr)->gXpos = gElements.at(gr)->xPos() - gx;
1029
                        gElements.at(gr)->gYpos = gElements.at(gr)->yPos() - gy;
1030
                        gElements.at(gr)->gWidth = gw;
1031
                        gElements.at(gr)->gHeight = gh;
7612 jghali 1032
                        GElements.append(gElements.at(gr));
1033
                }
7620 fschmid 1034
                neu->setRedrawBounding();
11705 fschmid 1035
                neu->setTextFlowMode(PageItem::TextFlowDisabled);
7640 fschmid 1036
                m_Doc->GroupCounter++;
7612 jghali 1037
        }
7597 jghali 1038
        delete( m_gc.pop() );
7315 jghali 1039
        return GElements;
1040
}
1041
 
9856 fschmid 1042
QList<PageItem*> SVGPlug::parseElement(const QDomElement &e)
7315 jghali 1043
{
9856 fschmid 1044
        QList<PageItem*> GElements;
7556 jghali 1045
        if (e.hasAttribute("id"))
1046
                m_nodeMap.insert(e.attribute("id"), e);
16887 jghali 1047
        QString STag = parseTagName(e);
1048
        if (STag == "g")
7315 jghali 1049
        {
7612 jghali 1050
                GElements = parseGroup( e );
7315 jghali 1051
                return GElements;
1052
        }
16887 jghali 1053
        if (STag == "defs")
7556 jghali 1054
                parseDefs(e);
16887 jghali 1055
        else if (STag == "a")
15171 jghali 1056
                GElements = parseA(e);
16887 jghali 1057
        else if (STag == "switch")
7315 jghali 1058
                GElements = parseSwitch(e);
16887 jghali 1059
        else if (STag == "symbol")
8507 jghali 1060
                GElements = parseSymbol(e);
16887 jghali 1061
        else if (STag == "use")
7556 jghali 1062
                GElements = parseUse(e);
16887 jghali 1063
        else if (STag == "linearGradient" || STag == "radialGradient" )
7315 jghali 1064
                parseGradient( e );
16887 jghali 1065
        else if (STag == "rect")
7612 jghali 1066
                GElements = parseRect(e);
16887 jghali 1067
        else if (STag == "ellipse")
7612 jghali 1068
                GElements = parseEllipse(e);
16887 jghali 1069
        else if (STag == "circle")
7612 jghali 1070
                GElements = parseCircle(e);
16887 jghali 1071
        else if (STag == "line")
7612 jghali 1072
                GElements = parseLine(e);
16887 jghali 1073
        else if (STag == "path")
7612 jghali 1074
                GElements = parsePath(e);
16887 jghali 1075
        else if (STag == "polyline" || STag == "polygon")
7612 jghali 1076
                GElements = parsePolyline(e);
16887 jghali 1077
        else if (STag == "text")
7612 jghali 1078
                GElements = parseText(e);
16887 jghali 1079
        else if (STag == "clipPath")
7605 jghali 1080
                parseClipPath(e);
16887 jghali 1081
        else if (STag == "desc")
7866 fschmid 1082
        {
1083
                if (groupLevel == 1)
1084
                        docDesc = e.text();
1085
        }
16887 jghali 1086
        else if (STag == "title")
7866 fschmid 1087
        {
1088
                if (groupLevel == 1)
1089
                        docTitle = e.text();
1090
        }
16887 jghali 1091
        else if (STag == "image")
12785 fschmid 1092
                GElements = parseImage(e);
16887 jghali 1093
/*      else if (STag == "i:pgf")
10493 fschmid 1094
        {
1095
                QByteArray cdat;
1096
                QByteArray ddat;
1097
                cdat = e.text().simplified();
1098
                QList<QByteArray> cdlist = cdat.split(' ');
1099
                for (int cd = 0; cd < cdlist.count(); cd++)
1100
                {
1101
                        ddat += QByteArray::fromBase64(cdlist[cd]);
1102
                }
1103
                QFile outf("/home/franz/testdata.txt");
1104
                outf.open(QIODevice::WriteOnly);
1105
                outf.write(ddat);
1106
                outf.close();
1107
                QString f2 = "/home/franz/testdata_decom.ai";
1108
                FILE *source = fopen("/home/franz/testdata.txt", "rb");
1109
                FILE *dest = fopen(f2, "wb");
1110
                int ret;
1111
                unsigned have;
1112
                z_stream strm;
1113
                char in[4096];
1114
                char out[4096];
1115
                strm.zalloc = Z_NULL;
1116
                strm.zfree = Z_NULL;
1117
                strm.opaque = Z_NULL;
1118
                strm.avail_in = 0;
1119
                strm.next_in = Z_NULL;
1120
                ret = inflateInit(&strm);
1121
                if (ret != Z_OK)
1122
                        return GElements;
1123
                do
1124
                {
1125
                        strm.avail_in = fread(in, 1, 4096, source);
1126
                        if (ferror(source))
1127
                        {
1128
                                (void)inflateEnd(&strm);
1129
                                return GElements;
1130
                        }
1131
                        if (strm.avail_in == 0)
1132
                                break;
1133
                        strm.next_in = (Bytef*)in;
1134
                        do
1135
                        {
1136
                                strm.avail_out = 4096;
1137
                                strm.next_out = (Bytef*)out;
1138
                                ret = inflate(&strm, Z_NO_FLUSH);
1139
                                assert(ret != Z_STREAM_ERROR);
1140
                                switch (ret)
1141
                                {
1142
                                        case Z_NEED_DICT:
1143
                                                ret = Z_DATA_ERROR;
1144
                                        case Z_DATA_ERROR:
1145
                                        case Z_MEM_ERROR:
1146
                                                (void)inflateEnd(&strm);
1147
                                                return GElements;
1148
                                }
1149
                                have = 4096 - strm.avail_out;
1150
                                if (fwrite(out, 1, have, dest) != have || ferror(dest))
1151
                                {
1152
                                        (void)inflateEnd(&strm);
1153
                                        return GElements;
1154
                                }
1155
                        }
1156
                        while (strm.avail_out == 0);
1157
                }
1158
                while (ret != Z_STREAM_END);
1159
                (void)inflateEnd(&strm);
1160
                fclose(source);
1161
                fclose(dest);
1162
        } */
7605 jghali 1163
/*      else if( STag == "image" )
7612 jghali 1164
                GElements = parseImage(e);
7504 fschmid 1165
        } */
16887 jghali 1166
        else if (!isIgnorableNodeName(STag))
7315 jghali 1167
        {
1168
                // warn if unsupported SVG feature are encountered
13385 jghali 1169
                if (!m_unsupportedFeatures.contains(STag))
1170
                {
1171
                        m_unsupportedFeatures.insert(STag, STag);
1172
                        qDebug() << QString("unsupported SVG feature: %1").arg(STag);
1173
                        unsupported = true;
1174
                }
7315 jghali 1175
        }
7612 jghali 1176
        return GElements;
1177
}
1178
 
9856 fschmid 1179
QList<PageItem*> SVGPlug::parseCircle(const QDomElement &e)
7612 jghali 1180
{
9856 fschmid 1181
        QList<PageItem*> CElements;
7612 jghali 1182
        double BaseX = m_Doc->currentPage()->xOffset();
1183
        double BaseY = m_Doc->currentPage()->yOffset();
1184
        double r = parseUnit( e.attribute( "r" ) );
1185
        double x = parseUnit( e.attribute( "cx" ) ) - r;
1186
        double y = parseUnit( e.attribute( "cy" ) ) - r;
1187
        setupNode(e);
9922 fschmid 1188
        SvgStyle *gc = m_gc.top();
7612 jghali 1189
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, r * 2.0, r * 2.0, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1190
        PageItem* ite = m_Doc->Items->at(z);
8501 cbradney 1191
        QMatrix mm = QMatrix();
7612 jghali 1192
        mm.translate(x, y);
1193
        ite->PoLine.map(mm);
1194
        FPoint wh = getMaxClipF(&ite->PoLine);
1195
        ite->setWidthHeight(wh.x(), wh.y());
1196
        finishNode(e, ite);
1197
        CElements.append(ite);
1198
        delete( m_gc.pop() );
1199
        return CElements;
1200
}
1201
 
9856 fschmid 1202
QList<PageItem*> SVGPlug::parseEllipse(const QDomElement &e)
7612 jghali 1203
{
9856 fschmid 1204
        QList<PageItem*> EElements;
7612 jghali 1205
        double BaseX = m_Doc->currentPage()->xOffset();
1206
        double BaseY = m_Doc->currentPage()->yOffset();
1207
        double rx = parseUnit( e.attribute( "rx" ) );
1208
        double ry = parseUnit( e.attribute( "ry" ) );
1209
        double x = parseUnit( e.attribute( "cx" ) ) - rx;
1210
        double y = parseUnit( e.attribute( "cy" ) ) - ry;
1211
        setupNode(e);
9922 fschmid 1212
        SvgStyle *gc = m_gc.top();
7612 jghali 1213
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, rx * 2.0, ry * 2.0, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1214
        PageItem* ite = m_Doc->Items->at(z);
8501 cbradney 1215
        QMatrix mm = QMatrix();
7612 jghali 1216
        mm.translate(x, y);
1217
        ite->PoLine.map(mm);
1218
        FPoint wh = getMaxClipF(&ite->PoLine);
1219
        ite->setWidthHeight(wh.x(), wh.y());
1220
        finishNode(e, ite);
1221
        EElements.append(ite);
1222
        delete( m_gc.pop() );
1223
        return EElements;
1224
}
1225
 
9856 fschmid 1226
QList<PageItem*> SVGPlug::parseImage(const QDomElement &e)
7612 jghali 1227
{
1228
        FPointArray clipPath;
9856 fschmid 1229
        QList<PageItem*> IElements;
7612 jghali 1230
        QString fname = e.attribute("xlink:href");
1231
        double BaseX = m_Doc->currentPage()->xOffset();
1232
        double BaseY = m_Doc->currentPage()->yOffset();
1233
        double x = e.attribute( "x" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x" ) );
1234
        double y = e.attribute( "y" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y" ) );
1235
        double w = e.attribute( "width" ).isEmpty() ? 1.0 : parseUnit( e.attribute( "width" ) );
1236
        double h = e.attribute( "height" ).isEmpty() ? 1.0 : parseUnit( e.attribute( "height" ) );
1237
        setupNode(e);
1238
        parseClipPathAttr(e, clipPath);
1239
        int z = m_Doc->itemAdd(PageItem::ImageFrame, PageItem::Unspecified, x+BaseX, y+BaseY, w, h, 1, m_Doc->toolSettings.dBrushPict, CommonStrings::None, true);
12795 fschmid 1240
        PageItem* ite = m_Doc->Items->at(z);
7612 jghali 1241
        if (!fname.isEmpty())
12785 fschmid 1242
        {
1243
                if (!fname.startsWith("data:"))
1244
                        m_Doc->LoadPict(fname, z);
1245
                else
1246
                {
1247
                        int startData = fname.indexOf(",");
1248
                        QString dataType = fname.left(startData);
1249
                        fname.remove(0, startData+1);
1250
                        QByteArray ba;
1251
                        ba.append(fname);
1252
                        if (dataType.contains("base64"))
1253
                                ba = QByteArray::fromBase64(ba);
12795 fschmid 1254
                        ite->tempImageFile = new QTemporaryFile(QDir::tempPath() + "/scribus_temp_svg_XXXXXX.png");
1255
                        ite->tempImageFile->open();
1256
                        QString fileName = getLongPathName(ite->tempImageFile->fileName());
1257
                        ite->tempImageFile->close();
1258
                        ite->isInlineImage = true;
12785 fschmid 1259
                        QImage img;
1260
                        img.loadFromData(ba);
12795 fschmid 1261
                        img.save(fileName, "PNG");
1262
                        m_Doc->LoadPict(fileName, z);
12785 fschmid 1263
                }
1264
        }
7612 jghali 1265
        if (clipPath.size() != 0)
1266
                ite->PoLine = clipPath.copy();
1267
        clipPath.resize(0);
1268
        ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
1269
        finishNode(e, ite);
1270
        IElements.append(ite);
1271
        delete( m_gc.pop() );
1272
        return IElements;
1273
}
1274
 
9856 fschmid 1275
QList<PageItem*> SVGPlug::parseLine(const QDomElement &e)
7612 jghali 1276
{
9856 fschmid 1277
        QList<PageItem*> LElements;
7612 jghali 1278
        double BaseX = m_Doc->currentPage()->xOffset();
1279
        double BaseY = m_Doc->currentPage()->yOffset();
1280
        double x1 = e.attribute( "x1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x1" ) );
1281
        double y1 = e.attribute( "y1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y1" ) );
1282
        double x2 = e.attribute( "x2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x2" ) );
1283
        double y2 = e.attribute( "y2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y2" ) );
1284
        setupNode(e);
9922 fschmid 1285
        SvgStyle *gc = m_gc.top();
11263 jghali 1286
        int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
7612 jghali 1287
        PageItem* ite = m_Doc->Items->at(z);
1288
        ite->PoLine.resize(4);
1289
        ite->PoLine.setPoint(0, FPoint(x1, y1));
1290
        ite->PoLine.setPoint(1, FPoint(x1, y1));
1291
        ite->PoLine.setPoint(2, FPoint(x2, y2));
1292
        ite->PoLine.setPoint(3, FPoint(x2, y2));
1293
        finishNode(e, ite);
1294
        LElements.append(ite);
1295
        delete( m_gc.pop() );
1296
        return LElements;
1297
}
1298
 
9856 fschmid 1299
QList<PageItem*> SVGPlug::parsePath(const QDomElement &e)
7612 jghali 1300
{
1301
        FPointArray pArray;
9856 fschmid 1302
        QList<PageItem*> PElements;
7612 jghali 1303
        double BaseX = m_Doc->currentPage()->xOffset();
1304
        double BaseY = m_Doc->currentPage()->yOffset();
1305
        setupNode(e);
9922 fschmid 1306
        SvgStyle *gc = m_gc.top();
7612 jghali 1307
        PageItem::ItemType itype = parseSVG(e.attribute("d"), &pArray) ? PageItem::PolyLine : PageItem::Polygon;
1308
        int z = m_Doc->itemAdd(itype, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1309
        PageItem* ite = m_Doc->Items->at(z);
7678 fschmid 1310
        ite->fillRule = (gc->fillRule != "nonzero");
7612 jghali 1311
        ite->PoLine = pArray;
1312
        if (ite->PoLine.size() < 4)
7315 jghali 1313
        {
7612 jghali 1314
//                      m_Doc->m_Selection->addItem(ite);
1315
                tmpSel->addItem(ite);
1316
//                      m_Doc->itemSelection_DeleteItem();
1317
                m_Doc->itemSelection_DeleteItem(tmpSel);
1318
//                      m_Doc->m_Selection->clear();
1319
        }
1320
        else
1321
        {
1322
                finishNode(e, ite);
1323
                PElements.append(ite);
1324
        }
1325
        delete( m_gc.pop() );
1326
        return PElements;
1327
}
1328
 
9856 fschmid 1329
QList<PageItem*> SVGPlug::parsePolyline(const QDomElement &e)
7612 jghali 1330
{
1331
        int z;
9856 fschmid 1332
        QList<PageItem*> PElements;
7612 jghali 1333
        double BaseX = m_Doc->currentPage()->xOffset();
1334
        double BaseY = m_Doc->currentPage()->yOffset();
1335
        setupNode(e);
9922 fschmid 1336
        SvgStyle *gc = m_gc.top();
7612 jghali 1337
        QString points = e.attribute( "points" );
1338
        if (!points.isEmpty())
1339
        {
16887 jghali 1340
                QString tagName = parseTagName(e);
10394 cbradney 1341
                points = points.simplified().replace(',', " ");
10603 fschmid 1342
                QStringList pointList = points.split( ' ', QString::SkipEmptyParts );
16887 jghali 1343
                if ((tagName == "polygon" ) && (pointList.count() > 4))
7612 jghali 1344
                        z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1345
                else
1346
                        z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
7315 jghali 1347
                PageItem* ite = m_Doc->Items->at(z);
7612 jghali 1348
                ite->fillRule = (gc->fillRule != "nonzero");
1349
                ite->PoLine.resize(0);
8237 avox 1350
                ite->PoLine.svgInit();
7612 jghali 1351
                bool bFirst = true;
1352
                double x = 0.0;
1353
                double y = 0.0;
1354
                for( QStringList::Iterator it = pointList.begin(); it != pointList.end(); it++ )
217 Franz 1355
                {
7612 jghali 1356
                        if( bFirst )
217 Franz 1357
                        {
13460 jghali 1358
                                x = ScCLocale::toDoubleC(*(it++));
1359
                                y = ScCLocale::toDoubleC(*it);
8252 jghali 1360
                                ite->PoLine.svgMoveTo(x, y);
7612 jghali 1361
                                bFirst = false;
68 Franz 1362
                        }
1363
                        else
7315 jghali 1364
                        {
13460 jghali 1365
                                x = ScCLocale::toDoubleC(*(it++));
1366
                                y = ScCLocale::toDoubleC(*it);
8252 jghali 1367
                                ite->PoLine.svgLineTo(x, y);
7315 jghali 1368
                        }
217 Franz 1369
                }
16887 jghali 1370
                if (( tagName == "polygon" ) && (pointList.count() > 4))
8237 avox 1371
                        ite->PoLine.svgClosePath();
7612 jghali 1372
                else
1373
                        ite->convertTo(PageItem::PolyLine);
1374
                finishNode(e, ite);
1375
                PElements.append(ite);
7315 jghali 1376
        }
1377
        delete( m_gc.pop() );
7612 jghali 1378
        return PElements;
7315 jghali 1379
}
1380
 
9856 fschmid 1381
QList<PageItem*> SVGPlug::parseRect(const QDomElement &e)
7612 jghali 1382
{
9856 fschmid 1383
        QList<PageItem*> RElements;
7612 jghali 1384
        double BaseX = m_Doc->currentPage()->xOffset();
1385
        double BaseY = m_Doc->currentPage()->yOffset();
1386
        double x = parseUnit( e.attribute( "x" ) );
1387
        double y = parseUnit( e.attribute( "y" ) );
1388
        double width = parseUnit( e.attribute( "width" ));
1389
        double height = parseUnit( e.attribute( "height" ) );
1390
        double rx = e.attribute( "rx" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "rx" ) );
1391
        double ry = e.attribute( "ry" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "ry" ) );
1392
        setupNode(e);
9922 fschmid 1393
        SvgStyle *gc = m_gc.top();
7612 jghali 1394
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, width, height, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1395
        PageItem* ite = m_Doc->Items->at(z);
1396
        if ((rx != 0) || (ry != 0))
1397
        {
8562 jghali 1398
                ite->setCornerRadius(qMax(rx, ry));
7612 jghali 1399
                ite->SetFrameRound();
1400
                m_Doc->setRedrawBounding(ite);
1401
        }
8501 cbradney 1402
        QMatrix mm = QMatrix();
7612 jghali 1403
        mm.translate(x, y);
1404
        ite->PoLine.map(mm);
1405
        FPoint wh = getMaxClipF(&ite->PoLine);
1406
        ite->setWidthHeight(wh.x(), wh.y());
1407
        finishNode(e, ite);
1408
        RElements.append(ite);
1409
        delete( m_gc.pop() );
1410
        return RElements;
1411
}
1412
 
9856 fschmid 1413
QList<PageItem*> SVGPlug::parseText(const QDomElement &e)
7315 jghali 1414
{
9856 fschmid 1415
        QList<PageItem*> GElements;
7612 jghali 1416
        setupNode(e);
12725 jghali 1417
        double chunkWidth = 0;
10785 jghali 1418
        FPoint currentPos = parseTextPosition(e);
12725 jghali 1419
        SvgStyle *gc      = m_gc.top();
1420
        if (gc->textAnchor != "start")
1421
                getTextChunkWidth(e, chunkWidth);
12719 fschmid 1422
        for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
7315 jghali 1423
        {
16887 jghali 1424
                if (n.isElement() && (parseTagName(n.toElement()) == "tspan"))
217 Franz 1425
                {
12725 jghali 1426
                        QList<PageItem*> el = parseTextSpan(n.toElement(), currentPos, chunkWidth);
9856 fschmid 1427
                        for (int ec = 0; ec < el.count(); ++ec)
215 Franz 1428
                                GElements.append(el.at(ec));
217 Franz 1429
                }
10785 jghali 1430
                if (n.isText())
1431
                {
12725 jghali 1432
                        QList<PageItem*> el = parseTextNode(n.toText(), currentPos, chunkWidth);
10785 jghali 1433
                        for (int ec = 0; ec < el.count(); ++ec)
1434
                                GElements.append(el.at(ec));
1435
                }
12719 fschmid 1436
        }
7612 jghali 1437
        delete( m_gc.pop() );
7315 jghali 1438
        return GElements;
1439
}
12725 jghali 1440
 
1441
QList<PageItem*> SVGPlug::parseTextSpan(const QDomElement& e, FPoint& currentPos, double chunkW)
7315 jghali 1442
{
9856 fschmid 1443
        QList<PageItem*> GElements;
12725 jghali 1444
        setupNode(e);
1445
        currentPos   = parseTextPosition(e, &currentPos);
1446
        SvgStyle *gc = m_gc.top();
1447
        if ((e.hasAttribute("x") || e.hasAttribute("y")) && (gc->textAnchor != "start"))
12718 fschmid 1448
        {
12725 jghali 1449
                chunkW = 0;
1450
                getTextChunkWidth(e, chunkW);
12718 fschmid 1451
        }
12725 jghali 1452
        for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
12718 fschmid 1453
        {
16887 jghali 1454
                if (n.isElement() && (n.toElement().localName() == "tspan"))
12718 fschmid 1455
                {
12725 jghali 1456
                        QList<PageItem*> el = parseTextSpan(n.toElement(), currentPos, chunkW);
1457
                        for (int ec = 0; ec < el.count(); ++ec)
1458
                                GElements.append(el.at(ec));
12718 fschmid 1459
                }
12725 jghali 1460
                if (n.isText())
12718 fschmid 1461
                {
12725 jghali 1462
                        QList<PageItem*> el = parseTextNode(n.toText(), currentPos, chunkW);
1463
                        for (int ec = 0; ec < el.count(); ++ec)
1464
                                GElements.append(el.at(ec));
12718 fschmid 1465
                }
1466
        }
12725 jghali 1467
        delete( m_gc.pop() );
12718 fschmid 1468
        return GElements;
1469
}
12725 jghali 1470
 
1471
QList<PageItem*> SVGPlug::parseTextNode(const QDomText& e, FPoint& currentPos, double chunkW)
12718 fschmid 1472
{
1473
        QList<PageItem*> GElements;
1474
        double BaseX  = m_Doc->currentPage()->xOffset();
1475
        double BaseY  = m_Doc->currentPage()->yOffset();
1476
        double StartX = currentPos.x(), StartY = currentPos.y();
12725 jghali 1477
 
1478
        QString textString = e.data().simplified();
10785 jghali 1479
        if ( textString.isEmpty() )
1480
                return GElements;
1481
 
10638 jghali 1482
        SvgStyle *gc   = m_gc.top();
1483
        QFont textFont = getFontFromStyle(*gc);
1484
        QFontMetrics fm(textFont);
1485
    double width   = fm.width(textString);
1486
 
1487
        if( gc->textAnchor == "middle" )
12725 jghali 1488
                StartX -= chunkW / 2.0;
10638 jghali 1489
        else if( gc->textAnchor == "end")
12725 jghali 1490
                StartX -= chunkW;
10638 jghali 1491
 
1492
        FPointArray textPath;
1493
        QString textFillColor   = gc->FillCol;
1494
        QString textStrokeColor = gc->StrokeCol;
1495
        QPainterPath painterPath;
1496
        painterPath.addText( StartX, StartY, textFont, textString );
1497
        textPath.fromQPainterPath(painterPath);
1498
        if (textPath.size() > 0)
1499
        {
12725 jghali 1500
//              double  lineWidth = 0.0;
10638 jghali 1501
                int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, textFillColor, textStrokeColor, true);
1502
                PageItem* ite = m_Doc->Items->at(z);
1503
                ite->PoLine = textPath;
1504
                finishNode(e, ite);
1505
                GElements.append(ite);
1506
        }
10785 jghali 1507
        currentPos.setX( currentPos.x() + width );
10638 jghali 1508
        return GElements;
7315 jghali 1509
}
12725 jghali 1510
 
9856 fschmid 1511
QList<PageItem*> SVGPlug::parseSwitch(const QDomElement &e)
7315 jghali 1512
{
1513
        QString href;
1514
        QStringList hrefs;
9856 fschmid 1515
        QList<PageItem*> SElements;
7315 jghali 1516
        for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
1517
        {
1518
                QDomElement de = n.toElement();
16887 jghali 1519
                QString STag = parseTagName(de);
7315 jghali 1520
                if (STag == "foreignObject")
217 Franz 1521
                {
7315 jghali 1522
                        if (de.hasAttribute("xlink:href"))
217 Franz 1523
                        {
7315 jghali 1524
                                href = de.attribute("xlink:href").mid(1);
1525
                                if (!href.isEmpty())
1526
                                        hrefs.append(href);
217 Franz 1527
                        }
7315 jghali 1528
                        for (QDomNode n1 = de.firstChild(); !n1.isNull(); n1 = n1.nextSibling())
217 Franz 1529
                        {
7315 jghali 1530
                                QDomElement de1 = n1.toElement();
1531
                                if (de1.hasAttribute("xlink:href"))
296 Franz 1532
                                {
7315 jghali 1533
                                        href = de1.attribute("xlink:href").mid(1);
1534
                                        if (!href.isEmpty())
1535
                                                hrefs.append(href);
298 Franz 1536
                                }
217 Franz 1537
                        }
1538
                }
7315 jghali 1539
                else
1540
                {
1541
                        if (de.hasAttribute("requiredExtensions") || de.hasAttribute("requiredFeatures"))
1542
                                continue;
1543
                        else if (de.hasAttribute("id") && hrefs.contains(de.attribute("id")))
1544
                                continue;
1545
                        else
1546
                        {
1547
                                SElements = parseElement(de);
1548
                                if (SElements.count() > 0)
1549
                                        break;
1550
                        }
1551
                }
217 Franz 1552
        }
7315 jghali 1553
        return SElements;
68 Franz 1554
}
1555
 
9856 fschmid 1556
QList<PageItem*> SVGPlug::parseSymbol(const QDomElement &e)
8507 jghali 1557
{
9856 fschmid 1558
        QList<PageItem*> SElements;
12266 jghali 1559
        QString id = e.attribute("id");
8507 jghali 1560
        if( !id.isEmpty() )
1561
                m_nodeMap.insert(id, e);
1562
        return SElements;
1563
}
1564
 
9856 fschmid 1565
QList<PageItem*> SVGPlug::parseUse(const QDomElement &e)
7556 jghali 1566
{
9856 fschmid 1567
        QList<PageItem*> UElements;
12266 jghali 1568
        setupNode(e);
1569
        if( e.hasAttribute("x") || e.hasAttribute("y") )
1570
        {
1571
                QMatrix matrix;
13460 jghali 1572
                double  xAtt = ScCLocale::toDoubleC(e.attribute("x", "0.0"));
1573
                double  yAtt = ScCLocale::toDoubleC(e.attribute("y", "0.0"));
12266 jghali 1574
                SvgStyle *gc = m_gc.top();
1575
                gc->matrix   = QMatrix(1.0, 0.0, 0.0, 1.0, xAtt, yAtt) * gc->matrix;
1576
        }
1577
        QString href = e.attribute("xlink:href").mid(1);
1578
        QMap<QString, QDomElement>::Iterator it = m_nodeMap.find(href);
1579
        if (it != m_nodeMap.end())
1580
        {
1581
                QDomElement elem = it.value().toElement();
16887 jghali 1582
                if (parseTagName(elem) == "symbol" )
12266 jghali 1583
                        UElements = parseGroup(elem);
1584
                else
1585
                        UElements = parseElement(elem);
1586
        }
1587
        delete (m_gc.pop());
7556 jghali 1588
        return UElements;
1589
}
1590
 
10638 jghali 1591
QFont SVGPlug::getFontFromStyle(SvgStyle& style)
1592
{
1593
        QFont font(QApplication::font());
1594
        font.setStyleStrategy( QFont::PreferOutline );
1595
 
1596
        if (!style.FontFamily.isEmpty())
1597
                font.setFamily(style.FontFamily);
1598
 
1599
        if (!style.FontStyle.isEmpty())
1600
        {
1601
                if (style.FontStyle == "normal")
1602
                        font.setStyle(QFont::StyleNormal);
1603
                else if (style.FontStyle == "italic")
1604
                        font.setStyle(QFont::StyleItalic);
1605
                else if (style.FontStyle == "oblique")
1606
                        font.setStyle(QFont::StyleOblique);
1607
        }
1608
 
1609
        if (!style.FontWeight.isEmpty())
1610
        {
1611
                if (style.FontWeight == "normal")
1612
                        font.setWeight(QFont::Normal);
1613
                else if (style.FontWeight == "bold")
1614
                        font.setWeight(QFont::Bold);
1615
                else if (style.FontWeight == "bolder")
1616
                        font.setWeight(QFont::DemiBold);
1617
                else if (style.FontWeight == "lighter")
1618
                        font.setWeight(QFont::Light);
1619
                else
1620
                {
1621
                        bool weightIsNum = false;
1622
                        int  fontWeight  = style.FontWeight.toInt(&weightIsNum);
1623
                        if (weightIsNum)
1624
                        {
1625
                                if (fontWeight == 100 || fontWeight == 200)
1626
                                        font.setWeight(QFont::Light);
1627
                                else if (fontWeight == 300 || fontWeight == 400)
1628
                                        font.setWeight(QFont::Normal);
1629
                                else if (fontWeight == 500 || fontWeight == 600)
1630
                                        font.setWeight(QFont::DemiBold);
1631
                                else if (fontWeight == 700 || fontWeight == 800)
1632
                                        font.setWeight(QFont::Bold);
1633
                                else if (fontWeight == 900)
1634
                                        font.setWeight(QFont::Black);
1635
                        }
1636
                }
1637
        }
1638
 
1639
        if (!style.FontStretch.isEmpty())
1640
        {
1641
                if (style.FontStretch == "normal")
1642
                        font.setStretch(QFont::Unstretched);
1643
                else if (style.FontStretch == "ultra-condensed")
1644
                        font.setStretch(QFont::UltraCondensed);
1645
                else if (style.FontStretch == "extra-condensed")
1646
                        font.setStretch(QFont::ExtraCondensed);
1647
                else if (style.FontStretch == "condensed")
1648
                        font.setStretch(QFont::Condensed);
1649
                else if (style.FontStretch == "semi-condensed")
1650
                        font.setStretch(QFont::SemiCondensed);
1651
                else if (style.FontStretch == "semi-expanded")
1652
                        font.setStretch(QFont::SemiExpanded);
1653
                else if (style.FontStretch == "expanded")
1654
                        font.setStretch(QFont::Expanded);
1655
                else if (style.FontStretch == "extra-expanded")
1656
                        font.setStretch(QFont::ExtraExpanded);
1657
                else if (style.FontStretch == "ultra-expanded")
1658
                        font.setStretch(QFont::UltraExpanded);
1659
                else if (style.FontStretch == "narrower")
1660
                        font.setStretch(QFont::SemiCondensed);
1661
                else if (style.FontStretch == "wider")
1662
                        font.setStretch(QFont::SemiExpanded);
1663
        }
12887 jghali 1664
        if (!style.textDecoration.isEmpty())
1665
        {
1666
                bool underline = false, overline  = false;
1667
                bool strikeOut = false;
1668
                if (style.textDecoration == "underline")
1669
                        underline = true;
1670
                else if (style.textDecoration == "overline")
1671
                        overline = true;
1672
                else if (style.textDecoration == "line-through")
1673
                        strikeOut = true;
1674
                font.setUnderline(underline);
1675
                font.setOverline(overline);
1676
                font.setStrikeOut(strikeOut);
1677
        }
17435 jghali 1678
        font.setPointSizeF(style.FontSize);
10638 jghali 1679
        return font;
1680
}
1681
 
8604 jghali 1682
QDomElement SVGPlug::getReferencedNode(const QDomElement &e)
1683
{
1684
        QDomElement ret;
1685
        QMap<QString, QDomElement>::Iterator it;
1686
        QString href = e.attribute("xlink:href").mid(1);
1687
        it = m_nodeMap.find(href);
1688
        if (it != m_nodeMap.end())
12287 jghali 1689
                ret = it.value().toElement();
8604 jghali 1690
        return ret;
1691
}
1692
 
12725 jghali 1693
bool SVGPlug::getTextChunkWidth(const QDomElement &e, double& width)
1694
{
1695
        bool doBreak = false;
1696
        setupNode(e);
1697
        QDomNode c = e.firstChild();
1698
        for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
1699
        {
16887 jghali 1700
                if (n.isElement() && (parseTagName(n.toElement()) == "tspan"))
12725 jghali 1701
                {
1702
                        QDomElement elem = n.toElement();
1703
                        if (elem.hasAttribute("x") || elem.hasAttribute("y"))
1704
                        {
1705
                                doBreak = true;
1706
                                break;
1707
                        }
1708
                        doBreak = getTextChunkWidth(n.toElement(), width);
1709
                        if (doBreak) break;
1710
                }
1711
                if (n.isText())
1712
                {
1713
                        QDomText text = n.toText();
1714
                        QString  textString = text.data().simplified();
1715
                        if (textString.length() > 0)
1716
                        {
1717
                                SvgStyle *gc   = m_gc.top();
1718
                                QFont textFont = getFontFromStyle(*gc);
1719
                                QFontMetrics fm(textFont);
1720
                                width += fm.width(textString);
1721
                        }
1722
                }
1723
        }
1724
        delete (m_gc.pop());
1725
        return doBreak;
1726
}
1727
 
68 Franz 1728
double SVGPlug::fromPercentage( const QString &s )
1729
{
10668 jghali 1730
        QString s1 = s;
1731
        if (s1.endsWith( ";" ))
1732
                s1 = s1.left(s1.length() - 1);
1733
        if (s1.endsWith( "%" ))
7556 jghali 1734
        {
10668 jghali 1735
                s1 = s1.left(s1.length() - 1);
13460 jghali 1736
                return ScCLocale::toDoubleC(s1) / 100.0;
7556 jghali 1737
        }
68 Franz 1738
        else
13460 jghali 1739
                return ScCLocale::toDoubleC(s1);
68 Franz 1740
}
1741
 
10638 jghali 1742
double SVGPlug::parseFontSize(const QString& fsize)
1743
{
1744
        bool noUnit  = true;
1745
        QString unit = fsize.right(2);
1746
        if (unit == "pt" || unit == "cm" || unit == "mm" ||
1747
                unit == "in" || unit == "px")
1748
        {
1749
                noUnit = false;
1750
        }
1751
        double value = parseUnit(fsize);
1752
        if (noUnit)
1753
                value *= 0.8;
1754
        return value;
1755
}
1756
 
68 Franz 1757
double SVGPlug::parseUnit(const QString &unit)
1758
{
693 fschmid 1759
        bool noUnit = false;
270 Franz 1760
        QString unitval=unit;
17435 jghali 1761
        if (unit.right( 2 ) == "pt")
270 Franz 1762
                unitval.replace( "pt", "" );
17435 jghali 1763
        else if (unit.right( 2 ) == "cm")
270 Franz 1764
                unitval.replace( "cm", "" );
17435 jghali 1765
        else if (unit.right( 2 ) == "mm")
270 Franz 1766
                unitval.replace( "mm" , "" );
17435 jghali 1767
        else if (unit.right( 2 ) == "in")
270 Franz 1768
                unitval.replace( "in", "" );
17435 jghali 1769
        else if (unit.right( 2 ) == "px")
270 Franz 1770
                unitval.replace( "px", "" );
693 fschmid 1771
        if (unitval == unit)
1772
                noUnit = true;
13460 jghali 1773
        double value = ScCLocale::toDoubleC(unitval);
17435 jghali 1774
        if (unit.right( 2 ) == "pt")
270 Franz 1775
                value = value;
17435 jghali 1776
        else if (unit.right( 2 ) == "cm")
270 Franz 1777
                value = ( value / 2.54 ) * 72;
17435 jghali 1778
        else if (unit.right( 2 ) == "mm")
270 Franz 1779
                value = ( value / 25.4 ) * 72;
17435 jghali 1780
        else if (unit.right( 2 ) == "in")
270 Franz 1781
                value = value * 72;
17435 jghali 1782
        else if (unit.right( 2 ) == "px")
865 fschmid 1783
                value = value * 0.8;
17435 jghali 1784
        else if (noUnit)
8252 jghali 1785
                value = value;
68 Franz 1786
        return value;
1787
}
1788
 
8501 cbradney 1789
QMatrix SVGPlug::parseTransform( const QString &transform )
68 Franz 1790
{
8501 cbradney 1791
        QMatrix ret;
12124 jghali 1792
        // Workaround for QString::split() bug when string ends with space
1793
        QString trans = transform.simplified();
68 Franz 1794
        // Split string for handling 1 transform statement at a time
12124 jghali 1795
        QStringList subtransforms = trans.split(')', QString::SkipEmptyParts);
68 Franz 1796
        QStringList::ConstIterator it = subtransforms.begin();
1797
        QStringList::ConstIterator end = subtransforms.end();
1798
        for(; it != end; ++it)
1799
        {
8501 cbradney 1800
                QMatrix result;
12124 jghali 1801
                QStringList subtransform = it->split('(', QString::SkipEmptyParts);
10398 cbradney 1802
                subtransform[0] = subtransform[0].trimmed().toLower();
10394 cbradney 1803
                subtransform[1] = subtransform[1].simplified();
68 Franz 1804
                QRegExp reg("[,( ]");
10603 fschmid 1805
                QStringList params = subtransform[1].split(reg, QString::SkipEmptyParts);
68 Franz 1806
                if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
1807
                        subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
1808
                if(subtransform[0] == "rotate")
1809
                {
1810
                        if(params.count() == 3)
1811
                        {
13460 jghali 1812
                                double x = ScCLocale::toDoubleC(params[1]);
1813
                                double y = ScCLocale::toDoubleC(params[2]);
68 Franz 1814
                                result.translate(x, y);
13460 jghali 1815
                                result.rotate(ScCLocale::toDoubleC(params[0]));
68 Franz 1816
                                result.translate(-x, -y);
1817
                        }
1818
                        else
13460 jghali 1819
                                result.rotate(ScCLocale::toDoubleC(params[0]));
68 Franz 1820
                }
1821
                else if(subtransform[0] == "translate")
1822
                {
1823
                        if(params.count() == 2)
13460 jghali 1824
                                result.translate(ScCLocale::toDoubleC(params[0]), ScCLocale::toDoubleC(params[1]));
68 Franz 1825
                        else    // Spec : if only one param given, assume 2nd param to be 0
13460 jghali 1826
                                result.translate(ScCLocale::toDoubleC(params[0]), 0);
68 Franz 1827
                }
1828
                else if(subtransform[0] == "scale")
1829
                {
1830
                        if(params.count() == 2)
13460 jghali 1831
                                result.scale(ScCLocale::toDoubleC(params[0]), ScCLocale::toDoubleC(params[1]));
68 Franz 1832
                        else    // Spec : if only one param given, assume uniform scaling
13460 jghali 1833
                                result.scale(ScCLocale::toDoubleC(params[0]), ScCLocale::toDoubleC(params[0]));
68 Franz 1834
                }
1835
                else if(subtransform[0] == "skewx")
13460 jghali 1836
                        result.shear(tan(ScCLocale::toDoubleC(params[0]) * 0.01745329251994329576), 0.0F);
68 Franz 1837
                else if(subtransform[0] == "skewy")
13460 jghali 1838
                        result.shear(0.0F, tan(ScCLocale::toDoubleC(params[0]) * 0.01745329251994329576));
68 Franz 1839
                else if(subtransform[0] == "matrix")
1840
                {
1841
                        if(params.count() >= 6)
332 Franz 1842
                        {
13460 jghali 1843
                                double sx = ScCLocale::toDoubleC(params[0]);
1844
                                double sy = ScCLocale::toDoubleC(params[3]);
1845
                                double p1 = ScCLocale::toDoubleC(params[1]);
1846
                                double p2 = ScCLocale::toDoubleC(params[2]);
1847
                                double p4 = ScCLocale::toDoubleC(params[4]);
1848
                                double p5 = ScCLocale::toDoubleC(params[5]);
1849
                                result.setMatrix(sx, p1, p2, sy, p4, p5);
332 Franz 1850
                        }
68 Franz 1851
                }
6611 jghali 1852
                ret = result * ret;
68 Franz 1853
        }
2597 fschmid 1854
        return ret;
68 Franz 1855
}
1856
 
1857
const char * SVGPlug::getCoord( const char *ptr, double &number )
1858
{
1859
        int integer, exponent;
1860
        double decimal, frac;
1861
        int sign, expsign;
1862
 
1863
        exponent = 0;
1864
        integer = 0;
1865
        frac = 1.0;
1866
        decimal = 0;
1867
        sign = 1;
1868
        expsign = 1;
1869
 
1870
        // read the sign
1871
        if(*ptr == '+')
1872
                ptr++;
1873
        else if(*ptr == '-')
1874
        {
1875
                ptr++;
1876
                sign = -1;
1877
        }
1878
 
1879
        // read the integer part
1880
        while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1881
                integer = (integer * 10) + *(ptr++) - '0';
1882
        if(*ptr == '.') // read the decimals
217 Franz 1883
        {
68 Franz 1884
                ptr++;
1885
                while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1886
                        decimal += (*(ptr++) - '0') * (frac *= 0.1);
217 Franz 1887
        }
68 Franz 1888
 
1889
        if(*ptr == 'e' || *ptr == 'E') // read the exponent part
1890
        {
1891
                ptr++;
1892
 
1893
                // read the sign of the exponent
1894
                if(*ptr == '+')
1895
                        ptr++;
1896
                else if(*ptr == '-')
1897
                {
1898
                        ptr++;
1899
                        expsign = -1;
1900
                }
1901
 
1902
                exponent = 0;
1903
                while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1904
                {
1905
                        exponent *= 10;
1906
                        exponent += *ptr - '0';
1907
                        ptr++;
1908
                }
217 Franz 1909
        }
68 Franz 1910
        number = integer + decimal;
80 Franz 1911
        number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) );
68 Franz 1912
        // skip the following space
1913
        if(*ptr == ' ')
1914
                ptr++;
1915
 
1916
        return ptr;
1917
}
1918
 
1919
bool SVGPlug::parseSVG( const QString &s, FPointArray *ite )
1920
{
8253 jghali 1921
        return ite->parseSVG(s);
68 Franz 1922
}
1923
 
1924
 
1925
QColor SVGPlug::parseColorN( const QString &rgbColor )
1926
{
1927
        int r, g, b;
10398 cbradney 1928
        keywordToRGB( rgbColor.toLower(), r, g, b );
68 Franz 1929
        return QColor( r, g, b );
1930
}
1931
 
4645 subik 1932
 
68 Franz 1933
QString SVGPlug::parseColor( const QString &s )
1934
{
1935
        QColor c;
6286 jghali 1936
        QString ret = CommonStrings::None;
13391 jghali 1937
        if (s.length() > 11) // icc-color()
217 Franz 1938
        {
13391 jghali 1939
                int iccColorIndex  = s.indexOf("icc-color");
1940
                if (iccColorIndex >= 0)
1941
                {
1942
                        QString iccColorName = parseIccColor(s);
1943
                        if (iccColorName.length() > 0)
1944
                                return iccColorName;
1945
                }
1946
        }
1947
        if (s.startsWith( "rgb(" ) )
1948
        {
10394 cbradney 1949
                QString parse = s.trimmed();
10603 fschmid 1950
                QStringList colors = parse.split(',', QString::SkipEmptyParts);
68 Franz 1951
                QString r = colors[0].right( ( colors[0].length() - 4 ) );
1952
                QString g = colors[1];
1953
                QString b = colors[2].left( ( colors[2].length() - 1 ) );
13391 jghali 1954
                if (r.contains( "%" )