FreeCAD

Форк
0
/
QGSPage.cpp 
1146 строк · 40.0 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2020 Wanderer Fan <wandererfan@gmail.com>               *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
#include <cmath>
26

27
#include <QDomDocument>
28
#include <QFile>
29
#include <QPainter>
30
#include <QSvgGenerator>
31
#include <QTemporaryFile>
32
#include <QTextStream>
33
#endif
34

35
#include <App/Document.h>
36
#include <Base/Console.h>
37
#include <Base/Parameter.h>
38
#include <Gui/Command.h>
39
#include <Gui/Document.h>
40
#include <Gui/Selection.h>
41

42
#include <Mod/TechDraw/App/DrawHatch.h>
43
#include <Mod/TechDraw/App/DrawLeaderLine.h>
44
#include <Mod/TechDraw/App/DrawPage.h>
45
#include <Mod/TechDraw/App/DrawParametricTemplate.h>
46
#include <Mod/TechDraw/App/DrawProjGroup.h>
47
#include <Mod/TechDraw/App/DrawRichAnno.h>
48
#include <Mod/TechDraw/App/DrawSVGTemplate.h>
49
#include <Mod/TechDraw/App/DrawTemplate.h>
50
#include <Mod/TechDraw/App/DrawUtil.h>
51
#include <Mod/TechDraw/App/DrawViewAnnotation.h>
52
#include <Mod/TechDraw/App/DrawViewBalloon.h>
53
#include <Mod/TechDraw/App/DrawViewClip.h>
54
#include <Mod/TechDraw/App/DrawViewCollection.h>
55
#include <Mod/TechDraw/App/DrawViewDimension.h>
56
#include <Mod/TechDraw/App/DrawViewImage.h>
57
#include <Mod/TechDraw/App/DrawViewPart.h>
58
#include <Mod/TechDraw/App/DrawViewSection.h>
59
#include <Mod/TechDraw/App/DrawViewSpreadsheet.h>
60
#include <Mod/TechDraw/App/DrawViewSymbol.h>
61
#include <Mod/TechDraw/App/DrawWeldSymbol.h>
62
#include <Mod/TechDraw/App/Preferences.h>
63

64
#include "QGIDrawingTemplate.h"
65
#include "QGILeaderLine.h"
66
#include "QGIProjGroup.h"
67
#include "QGIRichAnno.h"
68
#include "QGISVGTemplate.h"
69
#include "QGITemplate.h"
70
#include "QGIViewAnnotation.h"
71
#include "QGIViewBalloon.h"
72
#include "QGIViewClip.h"
73
#include "QGIViewCollection.h"
74
#include "QGIViewDimension.h"
75
#include "QGIViewImage.h"
76
#include "QGIViewPart.h"
77
#include "QGIViewSection.h"
78
#include "QGIViewSpreadsheet.h"
79
#include "QGIViewSymbol.h"
80
#include "QGIWeldSymbol.h"
81
#include "QGSPage.h"
82
#include "Rez.h"
83
#include "ViewProviderDrawingView.h"
84
#include "ViewProviderPage.h"
85
#include "ZVALUE.h"
86

87

88
// used SVG namespaces
89
#define CC_NS_URI "http://creativecommons.org/ns#"
90
#define DC_NS_URI "http://purl.org/dc/elements/1.1/"
91
#define RDF_NS_URI "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
92
#define INKSCAPE_NS_URI "http://www.inkscape.org/namespaces/inkscape"
93
#define SODIPODI_NS_URI "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
94

95
using namespace Gui;
96
using namespace TechDraw;
97
using namespace TechDrawGui;
98
using DU = DrawUtil;
99

100
QGSPage::QGSPage(ViewProviderPage* vpPage, QWidget* parent)
101
    : QGraphicsScene(parent), pageTemplate(nullptr), m_vpPage(nullptr)
102
{
103
    assert(vpPage);
104
    m_vpPage = vpPage;
105
    setItemIndexMethod(QGraphicsScene::BspTreeIndex);//the default
106
    //    setItemIndexMethod(QGraphicsScene::NoIndex);    //sometimes faster
107
}
108

109
void QGSPage::addChildrenToPage()
110
{
111
    //    Base::Console().Message("QGSP::addChildrenToPage()\n");
112
    // A fresh page is added and we iterate through its collected children and add these to Canvas View  -MLP
113
    // if docobj is a featureviewcollection (ex orthogroup), add its child views. if there are ever children that have children,
114
    // we'll have to make this recursive. -WF
115
    const std::vector<App::DocumentObject*>& grp = m_vpPage->getDrawPage()->Views.getValues();
116
    std::vector<App::DocumentObject*> childViews;
117
    for (std::vector<App::DocumentObject*>::const_iterator it = grp.begin(); it != grp.end();
118
         ++it) {
119
        attachView(*it);
120
        TechDraw::DrawViewCollection* collect = dynamic_cast<TechDraw::DrawViewCollection*>(*it);
121
        if (collect) {
122
            childViews = collect->Views.getValues();
123
            for (std::vector<App::DocumentObject*>::iterator itChild = childViews.begin();
124
                 itChild != childViews.end(); ++itChild) {
125
                attachView(*itChild);
126
            }
127
        }
128
    }
129
    //when restoring, it is possible for a Dimension to be loaded before the ViewPart it applies to
130
    //therefore we need to make sure parentage of the graphics representation is set properly. bit of a kludge.
131
    setDimensionGroups();
132
    setBalloonGroups();
133

134
    App::DocumentObject* obj = m_vpPage->getDrawPage()->Template.getValue();
135
    auto pageTemplate(dynamic_cast<TechDraw::DrawTemplate*>(obj));
136
    if (pageTemplate) {
137
        attachTemplate(pageTemplate);
138
        matchSceneRectToTemplate();
139
    }
140

141
    //    viewAll();
142
}
143

144
//********** template related routines *********
145

146
void QGSPage::attachTemplate(TechDraw::DrawTemplate* obj)
147
{
148
    //    Base::Console().Message("QGSP::attachTemplate()\n");
149
    setPageTemplate(obj);
150
}
151

152
void QGSPage::updateTemplate(bool forceUpdate)
153
{
154
    //    Base::Console().Message("QGSP::updateTemplate()\n");
155
    App::DocumentObject* templObj = m_vpPage->getDrawPage()->Template.getValue();
156
    // TODO: what if template has been deleted? templObj will be NULL. segfault?
157
    if (!templObj) {
158
        return;
159
    }
160

161
    if (m_vpPage->getDrawPage()->Template.isTouched() || templObj->isTouched()) {
162
        // Template is touched so update
163

164
        if (forceUpdate
165
            || (templObj && templObj->isTouched()
166
                && templObj->isDerivedFrom(TechDraw::DrawTemplate::getClassTypeId()))) {
167

168
            QGITemplate* qItemTemplate = getTemplate();
169

170
            if (qItemTemplate) {
171
                TechDraw::DrawTemplate* pageTemplate =
172
                    dynamic_cast<TechDraw::DrawTemplate*>(templObj);
173
                qItemTemplate->setTemplate(pageTemplate);
174
                qItemTemplate->updateView();
175
            }
176
        }
177
    }
178
}
179

180
QPointF QGSPage::getTemplateCenter()
181
{
182
    App::DocumentObject* obj = m_vpPage->getDrawPage()->Template.getValue();
183
    auto pageTemplate(dynamic_cast<TechDraw::DrawTemplate*>(obj));
184
    if (pageTemplate) {
185
        double cx = Rez::guiX(pageTemplate->Width.getValue()) / 2.0;
186
        double cy = -Rez::guiX(pageTemplate->Height.getValue()) / 2.0;
187
        return QPointF(cx, cy);
188
    }
189
    return QPointF(0.0, 0.0);
190
}
191

192
void QGSPage::matchSceneRectToTemplate(void)
193
{
194
    //    Base::Console().Message("QGSP::matchSceneRectToTemplate()\n");
195
    App::DocumentObject* obj = m_vpPage->getDrawPage()->Template.getValue();
196
    auto pageTemplate(dynamic_cast<TechDraw::DrawTemplate*>(obj));
197
    if (pageTemplate) {
198
        //make sceneRect 1 pagesize bigger in every direction
199
        double width = Rez::guiX(pageTemplate->Width.getValue());
200
        double height = Rez::guiX(pageTemplate->Height.getValue());
201
        setSceneRect(QRectF(-width, -2.0 * height, 3.0 * width, 3.0 * height));
202
    }
203
}
204

205
void QGSPage::setPageTemplate(TechDraw::DrawTemplate* templateFeat)
206
{
207
    //    Base::Console().Message("QGSP::setPageTemplate()\n");
208
    removeTemplate();
209

210
    if (templateFeat->isDerivedFrom(TechDraw::DrawParametricTemplate::getClassTypeId())) {
211
        pageTemplate = new QGIDrawingTemplate(this);
212
    }
213
    else if (templateFeat->isDerivedFrom(TechDraw::DrawSVGTemplate::getClassTypeId())) {
214
        pageTemplate = new QGISVGTemplate(this);
215
    }
216
    pageTemplate->setTemplate(templateFeat);
217
    pageTemplate->updateView();
218
}
219

220
QGITemplate* QGSPage::getTemplate() const { return pageTemplate; }
221

222
void QGSPage::removeTemplate()
223
{
224
    if (pageTemplate) {
225
        removeItem(pageTemplate);
226
        pageTemplate->deleteLater();
227
        pageTemplate = nullptr;
228
    }
229
}
230

231
//******* QGIView related routines
232

233
//! retrieve the QGIView objects currently in the scene
234
std::vector<QGIView*> QGSPage::getViews() const
235
{
236
    std::vector<QGIView*> result;
237
    QList<QGraphicsItem*> items = this->items();
238
    for (auto& v : items) {
239
        QGIView* qv = dynamic_cast<QGIView*>(v);
240
        if (qv) {
241
            result.push_back(qv);
242
        }
243
    }
244
    return result;
245
}
246

247
int QGSPage::addQView(QGIView* view)
248
{
249
    //don't add twice!
250
    QGIView* existing = getQGIVByName(view->getViewName());
251
    if (!existing) {
252
        addItem(view);
253

254
        TechDraw::DrawView *viewObj = view->getViewObject();
255
        // Preserve the desired position, as addToGroup() adjusts the child view's position
256
        QPointF viewPos(Rez::guiX(viewObj->X.getValue()), -Rez::guiX(viewObj->Y.getValue()));
257
        // Find if it belongs to a parent
258
        QGIView *parent = findParent(view);
259
        if (parent) {
260
            parent->addToGroup(view);
261
        }
262
        view->setPos(viewPos);
263

264
        auto viewProvider = dynamic_cast<ViewProviderDrawingView *>(QGIView::getViewProvider(view->getViewObject()));
265
        if (viewProvider) {
266
            view->setZValue(viewProvider->StackOrder.getValue());
267
        }
268

269
        view->updateView(true);
270
    }
271
    return 0;
272
}
273

274
int QGSPage::removeQView(QGIView* view)
275
{
276
    if (view) {
277
        removeQViewFromScene(view);
278
        delete view;
279
    }
280
    return 0;
281
}
282

283
int QGSPage::removeQViewByName(const char* name)
284
{
285
    std::vector<QGIView*> items = getViews();
286
    QString qsName = QString::fromUtf8(name);
287
    bool found = false;
288
    QGIView* ourItem = nullptr;
289
    for (auto& i : items) {
290
        if (qsName == i->data(1).toString()) {//is there a QGIV with this name in scene?
291
            found = true;
292
            ourItem = i;
293
            break;
294
        }
295
    }
296

297
    if (found) {
298
        int balloonItemType = QGraphicsItem::UserType + 140;
299
        if (ourItem->type() == balloonItemType) {
300
            QGIViewBalloon* balloon = dynamic_cast<QGIViewBalloon*>(ourItem);
301
            balloon->disconnect();
302
        }
303
        removeQViewFromScene(ourItem);
304
        delete ourItem;//commenting this prevents crash but means a small memory waste.
305
                       //alternate fix(?) is to change indexing/caching option in scene/view
306
    }
307

308
    return 0;
309
}
310

311
void QGSPage::removeQViewFromScene(QGIView* view)
312
{
313
    QGIView* qgParent = dynamic_cast<QGIView*>(view->parentItem());
314
    if (qgParent) {
315
        qgParent->removeChild(view);
316
    }
317
    else {
318
        removeItem(view);
319
    }
320
}
321

322
bool QGSPage::addView(const App::DocumentObject* obj)
323
{
324
    return attachView(const_cast<App::DocumentObject*>(obj));
325
}
326

327
bool QGSPage::attachView(App::DocumentObject* obj)
328
{
329
    //    Base::Console().Message("QGSP::attachView(%s)\n", obj->getNameInDocument());
330
    QGIView* existing = findQViewForDocObj(obj);
331
    if (existing)
332
        return true;
333

334
    auto typeId(obj->getTypeId());
335

336
    QGIView* qview(nullptr);
337

338
    if (typeId.isDerivedFrom(TechDraw::DrawViewSection::getClassTypeId())) {
339
        qview = addViewSection(static_cast<TechDraw::DrawViewSection*>(obj));
340
    }
341
    else if (typeId.isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId())) {
342
        qview = addViewPart(static_cast<TechDraw::DrawViewPart*>(obj));
343
    }
344
    else if (typeId.isDerivedFrom(TechDraw::DrawProjGroup::getClassTypeId())) {
345
        qview = addProjectionGroup(static_cast<TechDraw::DrawProjGroup*>(obj));
346
    }
347
    else if (typeId.isDerivedFrom(TechDraw::DrawViewCollection::getClassTypeId())) {
348
        qview = addDrawView(static_cast<TechDraw::DrawViewCollection*>(obj));
349
    }
350
    else if (typeId.isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId())) {
351
        qview = addViewDimension(static_cast<TechDraw::DrawViewDimension*>(obj));
352
    }
353
    else if (typeId.isDerivedFrom(TechDraw::DrawViewBalloon::getClassTypeId())) {
354
        qview = addViewBalloon(static_cast<TechDraw::DrawViewBalloon*>(obj));
355
    }
356
    else if (typeId.isDerivedFrom(TechDraw::DrawViewAnnotation::getClassTypeId())) {
357
        qview = addDrawViewAnnotation(static_cast<TechDraw::DrawViewAnnotation*>(obj));
358
    }
359
    else if (typeId.isDerivedFrom(TechDraw::DrawViewSymbol::getClassTypeId())) {
360
        qview = addDrawViewSymbol(static_cast<TechDraw::DrawViewSymbol*>(obj));
361
    }
362
    else if (typeId.isDerivedFrom(TechDraw::DrawViewClip::getClassTypeId())) {
363
        qview = addDrawViewClip(static_cast<TechDraw::DrawViewClip*>(obj));
364
    }
365
    else if (typeId.isDerivedFrom(TechDraw::DrawViewSpreadsheet::getClassTypeId())) {
366
        qview = addDrawViewSpreadsheet(static_cast<TechDraw::DrawViewSpreadsheet*>(obj));
367
    }
368
    else if (typeId.isDerivedFrom(TechDraw::DrawViewImage::getClassTypeId())) {
369
        qview = addDrawViewImage(static_cast<TechDraw::DrawViewImage*>(obj));
370
    }
371
    else if (typeId.isDerivedFrom(TechDraw::DrawLeaderLine::getClassTypeId())) {
372
        qview = addViewLeader(static_cast<TechDraw::DrawLeaderLine*>(obj));
373
    }
374
    else if (typeId.isDerivedFrom(TechDraw::DrawRichAnno::getClassTypeId())) {
375
        qview = addRichAnno(static_cast<TechDraw::DrawRichAnno*>(obj));
376
    }
377
    else if (typeId.isDerivedFrom(TechDraw::DrawWeldSymbol::getClassTypeId())) {
378
        qview = addWeldSymbol(static_cast<TechDraw::DrawWeldSymbol*>(obj));
379
    }
380
    else if (typeId.isDerivedFrom(TechDraw::DrawHatch::getClassTypeId())) {
381
        //Hatch is not attached like other Views (since it isn't really a View)
382
        return true;
383
    }
384

385
    return (qview != nullptr);
386
}
387

388
QGIView* QGSPage::addViewPart(TechDraw::DrawViewPart* partFeat)
389
{
390
    // Base::Console().Message("QGSP::addViewPart(%s)\n", partFeat->Label.getValue());
391
    auto viewPart(new QGIViewPart);
392

393
    viewPart->setViewPartFeature(partFeat);
394

395
    addQView(viewPart);
396
    // we need to install an event filter for any views derived from DrawViewPart
397
    viewPart->installSceneEventFilter(viewPart);
398
    return viewPart;
399
}
400

401
QGIView* QGSPage::addViewSection(DrawViewSection* sectionFeat)
402
{
403
    auto viewSection(new QGIViewSection);
404

405
    viewSection->setViewPartFeature(sectionFeat);
406

407
    addQView(viewSection);
408
    viewSection->installSceneEventFilter(viewSection);
409
    return viewSection;
410
}
411

412
QGIView* QGSPage::addProjectionGroup(TechDraw::DrawProjGroup* projGroupFeat)
413
{
414
    // Base::Console().Message("QGSP::addprojectionGroup(%s)\n", projGroupFeat->Label.getValue());
415
    auto qview(new QGIProjGroup);
416

417
    qview->setViewFeature(projGroupFeat);
418
    addQView(qview);
419
    qview->installSceneEventFilter(qview);
420

421
    return qview;
422
}
423

424
QGIView* QGSPage::addDrawView(TechDraw::DrawView* view)
425
{
426
    auto qview(new QGIView);
427

428
    qview->setViewFeature(view);
429
    addQView(qview);
430
    return qview;
431
}
432

433
QGIView* QGSPage::addDrawViewCollection(TechDraw::DrawViewCollection* collectionFeat)
434
{
435
    auto qview(new QGIViewCollection);
436

437
    qview->setViewFeature(collectionFeat);
438
    addQView(qview);
439
    return qview;
440
}
441

442
QGIView* QGSPage::addDrawViewAnnotation(TechDraw::DrawViewAnnotation* annoFeat)
443
{
444
    auto qview(new QGIViewAnnotation);
445

446
    qview->setViewAnnoFeature(annoFeat);
447

448
    addQView(qview);
449
    return qview;
450
}
451

452
QGIView* QGSPage::addDrawViewSymbol(TechDraw::DrawViewSymbol* symbolFeat)
453
{
454
    QGIViewSymbol *symbolView = new QGIViewSymbol;
455
    symbolView->setViewFeature(symbolFeat);
456

457
    addQView(symbolView);
458
    return symbolView;
459
}
460

461
QGIView* QGSPage::addDrawViewClip(TechDraw::DrawViewClip* view)
462
{
463
    auto qview(new QGIViewClip);
464

465
    qview->setPosition(Rez::guiX(view->X.getValue()), Rez::guiX(view->Y.getValue()));
466
    qview->setViewFeature(view);
467

468
    addQView(qview);
469
    return qview;
470
}
471

472
QGIView* QGSPage::addDrawViewSpreadsheet(TechDraw::DrawViewSpreadsheet* sheetFeat)
473
{
474
    auto qview(new QGIViewSpreadsheet);
475

476
    qview->setViewFeature(sheetFeat);
477

478
    addQView(qview);
479
    return qview;
480
}
481

482
QGIView* QGSPage::addDrawViewImage(TechDraw::DrawViewImage* imageFeat)
483
{
484
    auto qview(new QGIViewImage);
485

486
    qview->setViewFeature(imageFeat);
487

488
    addQView(qview);
489
    return qview;
490
}
491

492
QGIView* QGSPage::addViewBalloon(TechDraw::DrawViewBalloon* balloonFeat)
493
{
494
    //    Base::Console().Message("QGSP::addViewBalloon(%s)\n", balloonFeat->getNameInDocument());
495
    auto vBalloon(new QGIViewBalloon);
496

497
    addItem(vBalloon);
498

499
    vBalloon->setViewPartFeature(balloonFeat);
500

501
    QGIView* parent = nullptr;
502
    parent = findParent(vBalloon);
503

504
    if (parent) {
505
        addBalloonToParent(vBalloon, parent);
506
    }
507

508
    return vBalloon;
509
}
510

511
void QGSPage::addBalloonToParent(QGIViewBalloon* balloon, QGIView* parent)
512
{
513
    //    Base::Console().Message("QGSP::addBalloonToParent()\n");
514
    assert(balloon);
515
    assert(parent);//blow up if we don't have Dimension or Parent
516
    QPointF posRef(0., 0.);
517
    QPointF mapPos = balloon->mapToItem(parent, posRef);
518
    balloon->moveBy(-mapPos.x(), -mapPos.y());
519
    parent->addToGroup(balloon);
520
    balloon->setZValue(ZVALUE::DIMENSION);
521
}
522

523
//origin is in scene coordinates from QGViewPage
524
void QGSPage::createBalloon(QPointF origin, DrawView* parent)
525
{
526
    //    Base::Console().Message("QGSP::createBalloon(%s)\n", DrawUtil::formatVector(origin).c_str());
527
    std::string featName = getDrawPage()->getDocument()->getUniqueObjectName("Balloon");
528
    std::string pageName = getDrawPage()->getNameInDocument();
529

530
    Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Balloon"));
531
    Command::doCommand(Command::Doc,
532
                       "App.activeDocument().addObject('TechDraw::DrawViewBalloon', '%s')",
533
                       featName.c_str());
534
    Command::doCommand(Command::Doc, "App.activeDocument().%s.translateLabel('DrawViewBalloon', 'Balloon', '%s')",
535
              featName.c_str(), featName.c_str());
536

537
    TechDraw::DrawViewBalloon* balloon = dynamic_cast<TechDraw::DrawViewBalloon*>(
538
        getDrawPage()->getDocument()->getObject(featName.c_str()));
539
    if (!balloon) {
540
        throw Base::TypeError("QGSP::createBalloon - balloon not found\n");
541
    }
542
    Command::doCommand(Command::Doc,
543
                       "App.activeDocument().%s.SourceView = (App.activeDocument().%s)",
544
                       featName.c_str(), parent->getNameInDocument());
545
    QGIView* qgParent = getQGIVByName(parent->getNameInDocument());
546
    //convert from scene coords to qgParent coords and unscale
547
    QPointF parentOrigin = qgParent->mapFromScene(origin) / parent->getScale();
548
    balloon->setOrigin(parentOrigin);
549
    //convert origin to App side coords
550
    QPointF appOrigin = Rez::appPt(parentOrigin);
551
    appOrigin = DrawUtil::invertY(appOrigin);
552
    balloon->OriginX.setValue(appOrigin.x());
553
    balloon->OriginY.setValue(appOrigin.y());
554
    double textOffset = 20.0 / parent->getScale();
555
    balloon->X.setValue(appOrigin.x() + textOffset);
556
    balloon->Y.setValue(appOrigin.y() + textOffset);
557

558
    int idx = getDrawPage()->getNextBalloonIndex();
559
    balloon->Text.setValue(std::to_string(idx).c_str());
560

561
    Command::doCommand(Command::Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)",
562
                       pageName.c_str(), featName.c_str());
563

564
    Gui::Command::commitCommand();
565

566
    // Touch the parent feature so the balloon in tree view appears as a child
567
    parent->touch(true);
568
}
569

570
QGIView* QGSPage::addViewDimension(TechDraw::DrawViewDimension* dimFeat)
571
{
572
    auto dimGroup(new QGIViewDimension);
573

574
    addItem(dimGroup);
575

576
    dimGroup->setViewPartFeature(dimFeat);
577

578
    // Find if it belongs to a parent
579
    QGIView* parent = nullptr;
580
    parent = findParent(dimGroup);
581

582
    if (parent) {
583
        addDimToParent(dimGroup, parent);
584
    }
585

586
    return dimGroup;
587
}
588

589
void QGSPage::addDimToParent(QGIViewDimension* dim, QGIView* parent)
590
{
591
    //    Base::Console().Message("QGSP::addDimToParent()\n");
592
    assert(dim);
593
    assert(parent);//blow up if we don't have Dimension or Parent
594
    QPointF posRef(0., 0.);
595
    QPointF mapPos = dim->mapToItem(parent, posRef);
596
    dim->moveBy(-mapPos.x(), -mapPos.y());
597
    parent->addToGroup(dim);
598
    dim->setZValue(ZVALUE::DIMENSION);
599
}
600

601
QGIView* QGSPage::addViewLeader(TechDraw::DrawLeaderLine* leaderFeat)
602
{
603
    QGILeaderLine *leaderView = new QGILeaderLine;
604
    leaderView->setViewFeature(leaderFeat);
605

606
    addQView(leaderView);
607
    return leaderView;
608
}
609

610
QGIView* QGSPage::addRichAnno(TechDraw::DrawRichAnno* richFeat)
611
{
612
    QGIRichAnno *richView = new QGIRichAnno;
613
    richView->setViewFeature(richFeat);
614

615
    addQView(richView);
616
    return richView;
617
}
618

619
QGIView* QGSPage::addWeldSymbol(TechDraw::DrawWeldSymbol* weldFeat)
620
{
621
    QGIWeldSymbol *weldView = new QGIWeldSymbol;
622
    weldView->setViewFeature(weldFeat);
623

624
    addQView(weldView);
625
    return weldView;
626
}
627

628
void QGSPage::setDimensionGroups(void)
629
{
630
    const std::vector<QGIView*>& allItems = getViews();
631
    int dimItemType = QGraphicsItem::UserType + 106;
632

633
    for (auto& item : allItems) {
634
        if (item->type() == dimItemType && !item->group()) {
635
            QGIView* parent = findParent(item);
636
            if (parent) {
637
                QGIViewDimension* dim = dynamic_cast<QGIViewDimension*>(item);
638
                addDimToParent(dim, parent);
639
            }
640
        }
641
    }
642
}
643

644
void QGSPage::setBalloonGroups(void)
645
{
646
    const std::vector<QGIView*>& allItems = getViews();
647
    int balloonItemType = QGraphicsItem::UserType + 140;
648

649
    for (auto& item : allItems) {
650
        if (item->type() == balloonItemType && !item->group()) {
651
            QGIView* parent = findParent(item);
652
            if (parent) {
653
                QGIViewBalloon* balloon = dynamic_cast<QGIViewBalloon*>(item);
654
                addBalloonToParent(balloon, parent);
655
            }
656
        }
657
    }
658
}
659

660
//! find the graphic for a DocumentObject
661
QGIView* QGSPage::findQViewForDocObj(App::DocumentObject* obj) const
662
{
663
    //    Base::Console().Message("QGSP::findQViewForDocObj(%s)\n", obj->getNameInDocument());
664
    if (obj) {
665
        const std::vector<QGIView*> qviews = getViews();
666
        for (std::vector<QGIView*>::const_iterator it = qviews.begin(); it != qviews.end(); ++it) {
667
            if (strcmp(obj->getNameInDocument(), (*it)->getViewName()) == 0)
668
                return *it;
669
        }
670
    }
671
    return nullptr;
672
}
673

674
//! find the graphic for DocumentObject with name
675
QGIView* QGSPage::getQGIVByName(std::string name) const
676
{
677
    QList<QGraphicsItem*> qgItems = items();
678
    QList<QGraphicsItem*>::iterator it = qgItems.begin();
679
    for (; it != qgItems.end(); it++) {
680
        QGIView* qv = dynamic_cast<QGIView*>((*it));
681
        if (qv) {
682
            const char* qvName = qv->getViewName();
683
            if (name.compare(qvName) == 0) {
684
                return (qv);
685
            }
686
        }
687
    }
688
    return nullptr;
689
}
690

691
//find the parent of a QGIV based on the corresponding feature's parentage
692
QGIView* QGSPage::findParent(QGIView* view) const
693
{
694
    //    Base::Console().Message("QGSP::findParent(%s)\n", view->getViewName());
695
    const std::vector<QGIView*> qviews = getViews();
696
    TechDraw::DrawView* myFeat = view->getViewObject();
697

698
    TechDraw::DrawView *ownerFeat = myFeat->claimParent();
699
    if (ownerFeat) {
700
        QGIView *ownerView = getQGIVByName(ownerFeat->getNameInDocument());
701
        if (ownerView) {
702
            return ownerView;
703
        }
704
    }
705

706
    //If type is dimension we check references first
707
    TechDraw::DrawViewDimension* dim = nullptr;
708
    dim = dynamic_cast<TechDraw::DrawViewDimension*>(myFeat);
709
    if (dim) {
710
        std::vector<App::DocumentObject*> objs = dim->References2D.getValues();
711

712
        if (!objs.empty()) {
713
            std::vector<App::DocumentObject*> objs = dim->References2D.getValues();
714
            // Attach the dimension to the first object's group
715
            for (std::vector<QGIView*>::const_iterator it = qviews.begin(); it != qviews.end();
716
                 ++it) {
717
                if (strcmp((*it)->getViewName(), objs.at(0)->getNameInDocument()) == 0) {
718
                    return *it;
719
                }
720
            }
721
        }
722
    }
723

724
    //If type is balloon we check references first
725
    TechDraw::DrawViewBalloon* balloon = nullptr;
726
    balloon = dynamic_cast<TechDraw::DrawViewBalloon*>(myFeat);
727

728
    if (balloon) {
729
        App::DocumentObject* obj = balloon->SourceView.getValue();
730

731
        if (obj) {
732
            // Attach the Balloon to the first object's group
733
            for (std::vector<QGIView*>::const_iterator it = qviews.begin(); it != qviews.end();
734
                 ++it) {
735
                if (strcmp((*it)->getViewName(), obj->getNameInDocument()) == 0) {
736
                    return *it;
737
                }
738
            }
739
        }
740
    }
741

742
    // Not found a parent
743
    return nullptr;
744
}
745

746
bool QGSPage::hasQView(App::DocumentObject* obj)
747
{
748
    const std::vector<QGIView*>& views = getViews();
749
    std::vector<QGIView*>::const_iterator qview = views.begin();
750

751
    while (qview != views.end()) {
752
        // Unsure if we can compare pointers so rely on name
753
        if (strcmp((*qview)->getViewName(), obj->getNameInDocument()) == 0) {
754
            return true;
755
        }
756
        qview++;
757
    }
758

759
    return false;
760
}
761

762
void QGSPage::refreshViews()
763
{
764
    //    Base::Console().Message("QGSP::refreshViews()\n");
765
    QList<QGraphicsItem*> list = items();
766
    QList<QGraphicsItem*> qgiv;
767
    //find only QGIV's
768
    for (auto q : list) {
769
        QString viewFamily = QString::fromUtf8("QGIV");
770
        if (viewFamily == q->data(0).toString()) {
771
            qgiv.push_back(q);
772
        }
773
    }
774
    for (auto q : qgiv) {
775
        QGIView* itemView = dynamic_cast<QGIView*>(q);
776
        if (itemView) {
777
            itemView->updateView(true);
778
        }
779
    }
780
}
781

782
void QGSPage::findMissingViews(const std::vector<App::DocumentObject*>& list,
783
                               std::vector<App::DocumentObject*>& missing)
784
{
785
    for (std::vector<App::DocumentObject*>::const_iterator it = list.begin(); it != list.end();
786
         ++it) {
787

788
        if (!hasQView(*it))
789
            missing.push_back(*it);
790

791
        if ((*it)->isDerivedFrom<TechDraw::DrawViewCollection>()) {
792
            std::vector<App::DocumentObject*> missingChildViews;
793
            TechDraw::DrawViewCollection* collection =
794
                dynamic_cast<TechDraw::DrawViewCollection*>(*it);
795
            // Find Child Views recursively
796
            findMissingViews(collection->Views.getValues(), missingChildViews);
797

798
            // Append the views to current missing list
799
            for (std::vector<App::DocumentObject*>::const_iterator it = missingChildViews.begin();
800
                 it != missingChildViews.end(); ++it) {
801
                missing.push_back(*it);
802
            }
803
        }
804
    }
805
}
806

807
//this is time consuming. should only be used when there is a problem.
808
//Solve the situation where a DrawView belonging to this DrawPage has no QGraphicsItem in
809
//the QGScene for the DrawPage -or-
810
//a QGraphics item exists in the DrawPage's QGScene, but there is no corresponding DrawView
811
//in the DrawPage.
812
void QGSPage::fixOrphans(bool force)
813
{
814
    Q_UNUSED(force)
815

816
    // get all the DrawViews for this page, including the second level ones
817
    // if we ever have collections of collections, we'll need to revisit this
818
    TechDraw::DrawPage* thisPage = m_vpPage->getDrawPage();
819

820
    if (!thisPage->isAttachedToDocument())
821
        return;
822

823
    std::vector<App::DocumentObject*> pChildren = thisPage->getAllViews();
824

825
    // if dv doesn't have a graphic, make one
826
    for (auto& dv : pChildren) {
827
        if (dv->isRemoving())
828
            continue;
829
        QGIView* qv = findQViewForDocObj(dv);
830
        if (!qv)
831
            attachView(dv);
832
    }
833
    // if qView doesn't have a Feature on this Page, delete it
834
    std::vector<QGIView*> qvss = getViews();
835
    // qvss may contain an item and its child item(s) and to avoid to access a deleted item a QPointer is needed
836
    std::vector<QPointer<QGIView>> qvs;
837
    std::for_each(qvss.begin(), qvss.end(), [&qvs](QGIView* v) { qvs.emplace_back(v); });
838
    App::Document* doc = m_vpPage->getDrawPage()->getDocument();
839
    for (auto& qv : qvs) {
840
        if (!qv)
841
            continue;// already deleted?
842

843
        App::DocumentObject* obj = doc->getObject(qv->getViewName());
844
        if (!obj) {
845
            //no DrawView anywhere in Document
846
            removeQView(qv);
847
        }
848
        else {
849
            //DrawView exists in Document.  Does it belong to this DrawPage?
850
            int numParentPages = qv->getViewObject()->countParentPages();
851
            if (numParentPages == 0) {
852
                //DrawView does not belong to any DrawPage
853
                //remove QGItem from QGScene
854
                removeQView(qv);
855
            }
856
            else if (numParentPages == 1) {
857
                //Does DrawView belong to this DrawPage?
858
                TechDraw::DrawPage* parentPage = qv->getViewObject()->findParentPage();
859
                if (thisPage != parentPage) {
860
                    //DrawView does not belong to this DrawPage
861
                    //remove QGItem from QGScene
862
                    removeQView(qv);
863
                }
864
            }
865
            else if (numParentPages > 1) {
866
                //DrawView belongs to multiple DrawPages
867
                //check if this MDIViewPage corresponds to any parent DrawPage
868
                //if not, delete the QGItem
869
                std::vector<TechDraw::DrawPage*> potentialParentPages =
870
                    qv->getViewObject()->findAllParentPages();
871
                bool found = false;
872
                for (auto p : potentialParentPages) {
873
                    if (thisPage == p) {
874
                        found = true;
875
                        break;
876
                    }
877
                }
878
                if (!found) {
879
                    //none of the parent Pages for View correspond to this Page
880
                    removeQView(qv);
881
                }
882
            }
883
        }
884
    }
885
}
886

887
bool QGSPage::orphanExists(const char* viewName, const std::vector<App::DocumentObject*>& list)
888
{
889
    for (std::vector<App::DocumentObject*>::const_iterator it = list.begin(); it != list.end();
890
         ++it) {
891

892
        //Check child objects too recursively
893
        if ((*it)->isDerivedFrom(TechDraw::DrawViewCollection::getClassTypeId())) {
894
            TechDraw::DrawViewCollection* collection =
895
                dynamic_cast<TechDraw::DrawViewCollection*>(*it);
896
            if (orphanExists(viewName, collection->Views.getValues()))
897
                return true;
898
        }
899

900
        // Unsure if we can compare pointers so rely on name
901
        if (strcmp(viewName, (*it)->getNameInDocument()) == 0) {
902
            return true;
903
        }
904
    }
905
    return false;
906
}
907

908
//NOTE: this doesn't add missing views.  see fixOrphans()
909
void QGSPage::redrawAllViews()
910
{
911
    //    Base::Console().Message("QGSP::redrawAllViews() - views: %d\n", getViews().size());
912
    const std::vector<QGIView*>& upviews = getViews();
913
    for (std::vector<QGIView*>::const_iterator it = upviews.begin(); it != upviews.end(); ++it) {
914
        (*it)->updateView(true);
915
    }
916
}
917

918
//NOTE: this doesn't add missing views.   see fixOrphans()
919
void QGSPage::redraw1View(TechDraw::DrawView* dView)
920
{
921
    std::string dvName = dView->getNameInDocument();
922
    const std::vector<QGIView*>& upviews = getViews();
923
    for (std::vector<QGIView*>::const_iterator it = upviews.begin(); it != upviews.end(); ++it) {
924
        std::string qgivName = (*it)->getViewName();
925
        if (dvName == qgivName) {
926
            (*it)->updateView(true);
927
        }
928
    }
929
}
930

931
// RichTextAnno needs to know when it is rendering an Svg as the font size
932
// is handled differently in Svg compared to the screen or Pdf.
933
void QGSPage::setExportingSvg(bool enable)
934
{
935
    QList<QGraphicsItem*> sceneItems = items();
936
    for (auto& qgi : sceneItems) {
937
        QGIRichAnno* qgiRTA = dynamic_cast<QGIRichAnno*>(qgi);
938
        if (qgiRTA) {
939
            qgiRTA->setExportingSvg(enable);
940
        }
941
    }
942
}
943

944
void QGSPage::saveSvg(QString filename)
945
{
946
    // TODO: We only have m_vpPage because constructor gets passed a view provider...
947
    //NOTE: this makes wrong size pages in low-Rez
948
    TechDraw::DrawPage* page(m_vpPage->getDrawPage());
949

950
    const QString docName(QString::fromUtf8(page->getDocument()->getName()));
951
    const QString pageName(QString::fromUtf8(page->getNameInDocument()));
952
    QString svgDescription = QString::fromUtf8("Drawing page: ") + pageName
953
        + QString::fromUtf8(" exported from FreeCAD document: ") + docName;
954

955
    QSvgGenerator svgGen;
956
    QTemporaryFile temporaryFile;
957
    svgGen.setOutputDevice(&temporaryFile);
958

959
    // Set resolution in DPI. Use the actual one, i.e. Rez::guiX(inch)
960
    svgGen.setResolution(Rez::guiX(25.4));
961

962
    // Set size in pixels, which Qt recomputes using DPI to mm.
963
    int pixelWidth = Rez::guiX(page->getPageWidth());
964
    int pixelHeight = Rez::guiX(page->getPageHeight());
965
    svgGen.setSize(QSize(pixelWidth, pixelHeight));
966

967
    //"By default this property is set to QSize(-1, -1), which indicates that the generator should not output
968
    // the width and height attributes of the <svg> element."  >> but Inkscape won't read it without size info??
969
    svgGen.setViewBox(QRect(0, 0, pixelWidth, pixelHeight));
970

971
    svgGen.setTitle(QString::fromUtf8("FreeCAD SVG Export"));
972
    svgGen.setDescription(svgDescription);
973

974
    Gui::Selection().clearSelection();
975

976
    bool saveState = m_vpPage->getFrameState();
977
    m_vpPage->setFrameState(false);
978
    m_vpPage->setTemplateMarkers(false);
979
    setExportingSvg(true);
980

981
    // Here we temporarily hide the page template, because Qt would otherwise convert the SVG template
982
    // texts into series of paths, making the later document edits practically unfeasible.
983
    // We will insert the SVG template ourselves in the final XML postprocessing operation.
984
    QGISVGTemplate* svgTemplate = dynamic_cast<QGISVGTemplate*>(pageTemplate);
985
    bool templateVisible = false;
986
    if (svgTemplate) {
987
        templateVisible = svgTemplate->isVisible();
988
        svgTemplate->hide();
989
    }
990

991
    refreshViews();
992

993
    double width = Rez::guiX(page->getPageWidth());
994
    double height = Rez::guiX(page->getPageHeight());
995
    QRectF sourceRect(0.0, -height, width, height);
996
    QRectF targetRect(0.0, 0.0, width, height);
997

998
    Gui::Selection().clearSelection();
999
    QPainter p;
1000

1001
    p.begin(&svgGen);
1002
    render(&p, targetRect, sourceRect);//note: scene render, not item render!
1003
    p.end();
1004

1005
    m_vpPage->setFrameState(saveState);
1006
    m_vpPage->setTemplateMarkers(saveState);
1007
    setExportingSvg(false);
1008
    if (templateVisible && svgTemplate) {
1009
        svgTemplate->show();
1010
    }
1011

1012
    refreshViews();
1013

1014
    temporaryFile.close();
1015
    postProcessXml(temporaryFile, filename, pageName);
1016
}
1017

1018
static void removeEmptyGroups(QDomElement e)
1019
{
1020
    while (!e.isNull()) {
1021
        QDomElement next = e.nextSiblingElement();
1022
        if (e.hasChildNodes()) {
1023
            removeEmptyGroups(e.firstChildElement());
1024
        }
1025
        else if (e.tagName() == QLatin1String("g")) {
1026
            e.parentNode().removeChild(e);
1027
        }
1028
        e = next;
1029
    }
1030
}
1031

1032
void QGSPage::postProcessXml(QTemporaryFile& temporaryFile, QString fileName, QString pageName)
1033
{
1034
    QDomDocument exportDoc(QString::fromUtf8("SvgDoc"));
1035
    QFile file(temporaryFile.fileName());
1036
    if (!file.open(QIODevice::ReadOnly)) {
1037
        Base::Console().Error("QGSPage::ppsvg - tempfile open error\n");
1038
        return;
1039
    }
1040
    if (!exportDoc.setContent(&file)) {
1041
        Base::Console().Error("QGSPage::ppsvg - xml error\n");
1042
        file.close();
1043
        return;
1044
    }
1045
    file.close();
1046

1047
    QDomElement exportDocElem = exportDoc.documentElement();//root <svg>
1048

1049
    // Insert Freecad SVG namespace into namespace declarations
1050
    exportDocElem.setAttribute(QString::fromUtf8("xmlns:freecad"),
1051
                               QString::fromUtf8(FREECAD_SVG_NS_URI));
1052
    // Insert all namespaces used by TechDraw's page template SVGs
1053
    exportDocElem.setAttribute(QString::fromUtf8("xmlns:svg"), QString::fromUtf8(SVG_NS_URI));
1054
    exportDocElem.setAttribute(QString::fromUtf8("xmlns:cc"), QString::fromUtf8(CC_NS_URI));
1055
    exportDocElem.setAttribute(QString::fromUtf8("xmlns:dc"), QString::fromUtf8(DC_NS_URI));
1056
    exportDocElem.setAttribute(QString::fromUtf8("xmlns:rdf"), QString::fromUtf8(RDF_NS_URI));
1057
    exportDocElem.setAttribute(QString::fromUtf8("xmlns:inkscape"),
1058
                               QString::fromUtf8(INKSCAPE_NS_URI));
1059
    exportDocElem.setAttribute(QString::fromUtf8("xmlns:sodipodi"),
1060
                               QString::fromUtf8(SODIPODI_NS_URI));
1061

1062
    // Create the root group which will host the drawing group and the template group
1063
    QDomElement rootGroup = exportDoc.createElement(QString::fromUtf8("g"));
1064
    rootGroup.setAttribute(QString::fromUtf8("id"), pageName);
1065
    rootGroup.setAttribute(QString::fromUtf8("inkscape:groupmode"), QString::fromUtf8("layer"));
1066
    rootGroup.setAttribute(QString::fromUtf8("inkscape:label"), QString::fromUtf8("TechDraw"));
1067

1068
    // Now insert our template
1069
    QGISVGTemplate* svgTemplate = dynamic_cast<QGISVGTemplate*>(pageTemplate);
1070
    if (svgTemplate) {
1071
        DrawSVGTemplate* drawTemplate = svgTemplate->getSVGTemplate();
1072
        if (drawTemplate) {
1073
            QString templateSvg = drawTemplate->processTemplate();
1074
            QDomDocument templateResultDoc(QString::fromUtf8("SvgDoc"));
1075
            if (templateResultDoc.setContent(templateSvg)) {
1076
                QDomElement templateDocElem = templateResultDoc.documentElement();
1077

1078
                // Insert the template into a new group with id set to template name
1079
                QDomElement templateGroup = exportDoc.createElement(QString::fromUtf8("g"));
1080
                Base::FileInfo fi(drawTemplate->PageResult.getValue());
1081
                templateGroup.setAttribute(QString::fromUtf8("id"),
1082
                                           QString::fromUtf8(fi.fileName().c_str()));
1083
                templateGroup.setAttribute(QString::fromUtf8("style"),
1084
                                           QString::fromUtf8("stroke: none;"));
1085

1086
                // Scale the template group correctly
1087
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1088
                templateGroup.setAttribute(
1089
                    QString::fromUtf8("transform"),
1090
                    QString().sprintf("scale(%f, %f)", Rez::guiX(1.0), Rez::guiX(1.0)));
1091
#else
1092
                templateGroup.setAttribute(QString::fromUtf8("transform"),
1093
                                           QString::fromLatin1("scale(%1, %2)")
1094
                                               .arg(Rez::guiX(1.0), 0, 'f')
1095
                                               .arg(Rez::guiX(1.0), 0, 'f'));
1096
#endif
1097

1098
                // Finally, transfer all template document child nodes under the template group
1099
                while (!templateDocElem.firstChild().isNull()) {
1100
                    templateGroup.appendChild(templateDocElem.firstChild());
1101
                }
1102

1103
                rootGroup.appendChild(templateGroup);
1104
            }
1105
        }
1106
    }
1107

1108
    // Obtain the drawing group element, move it under root node and set its id to "DrawingContent"
1109
    QDomElement drawingGroup = exportDocElem.firstChildElement(QLatin1String("g"));
1110
    if (!drawingGroup.isNull()) {
1111
        drawingGroup.setAttribute(QString::fromUtf8("id"), QString::fromUtf8("DrawingContent"));
1112
        rootGroup.appendChild(drawingGroup);
1113
    }
1114
    exportDocElem.appendChild(rootGroup);
1115

1116
    // As icing on the cake, get rid of the empty <g>'s Qt SVG generator painting inserts.
1117
    removeEmptyGroups(exportDocElem);
1118

1119
    // Time to save our product
1120
    QFile outFile(fileName);
1121
    if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
1122
        Base::Console().Error("QGSP::ppxml - failed to open file for writing: %s\n",
1123
                              qPrintable(fileName));
1124
    }
1125

1126
    QTextStream stream(&outFile);
1127
    stream.setGenerateByteOrderMark(false);
1128
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1129
    stream.setCodec("UTF-8");
1130
#endif
1131

1132
    stream << exportDoc.toByteArray();
1133
    outFile.close();
1134
}
1135

1136
TechDraw::DrawPage* QGSPage::getDrawPage() { return m_vpPage->getDrawPage(); }
1137

1138
QColor QGSPage::getBackgroundColor()
1139
{
1140
    App::Color fcColor;
1141
    fcColor.setPackedValue(Preferences::getPreferenceGroup("Colors")->GetUnsigned("Background", 0x70707000));
1142
    return fcColor.asValue<QColor>();
1143
}
1144

1145

1146
#include <Mod/TechDraw/Gui/moc_QGSPage.cpp>
1147

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.