FreeCAD

Форк
0
/
TaskRichAnno.cpp 
578 строк · 19.0 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2019 WandererFan <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
# include <QDialog>
27
#endif
28

29
#include <App/Document.h>
30
#include <Base/Console.h>
31
#include <Base/Tools.h>
32
#include <Gui/Application.h>
33
#include <Gui/BitmapFactory.h>
34
#include <Gui/Command.h>
35
#include <Gui/Document.h>
36
#include <Gui/ViewProvider.h>
37
#include <Mod/TechDraw/App/DrawLeaderLine.h>
38
#include <Mod/TechDraw/App/DrawPage.h>
39
#include <Mod/TechDraw/App/DrawRichAnno.h>
40
#include <Mod/TechDraw/App/LineGroup.h>
41

42
#include "ui_TaskRichAnno.h"
43
#include "TaskRichAnno.h"
44
#include "mrichtextedit.h"
45
#include "PreferencesGui.h"
46
#include "QGIView.h"
47
#include "QGMText.h"
48
#include "QGSPage.h"
49
#include "Rez.h"
50
#include "ViewProviderPage.h"
51
#include "ViewProviderRichAnno.h"
52

53

54
using namespace Gui;
55
using namespace TechDraw;
56
using namespace TechDrawGui;
57

58
//ctor for edit
59
TaskRichAnno::TaskRichAnno(TechDrawGui::ViewProviderRichAnno* annoVP) :
60
    ui(new Ui_TaskRichAnno),
61
    m_annoVP(annoVP),
62
    m_baseFeat(nullptr),
63
    m_basePage(nullptr),
64
    m_annoFeat(nullptr),
65
    m_qgParent(nullptr),
66
    m_createMode(false),
67
    m_inProgressLock(false),
68
    m_btnOK(nullptr),
69
    m_btnCancel(nullptr),
70
    m_textDialog(nullptr),
71
    m_rte(nullptr)
72
{
73
    //existence of annoVP is guaranteed by caller being ViewProviderRichAnno.setEdit
74

75
    m_annoFeat = m_annoVP->getFeature();
76

77
    m_basePage = m_annoFeat->findParentPage();
78
    if (!m_basePage) {
79
        Base::Console().Error("TaskRichAnno - bad parameters (2).  Can not proceed.\n");
80
        return;
81
    }
82

83
    //m_baseFeat can be null
84
    App::DocumentObject* obj = m_annoFeat->AnnoParent.getValue();
85
    if (obj) {
86
        if ( obj->isDerivedFrom(TechDraw::DrawView::getClassTypeId()) )  {
87
            m_baseFeat = static_cast<TechDraw::DrawView*>(m_annoFeat->AnnoParent.getValue());
88
        }
89
    }
90

91
    Gui::Document* activeGui = Gui::Application::Instance->getDocument(m_basePage->getDocument());
92
    Gui::ViewProvider* vp = activeGui->getViewProvider(m_basePage);
93
    m_vpp = static_cast<ViewProviderPage*>(vp);
94

95
    m_qgParent = nullptr;
96
    if (m_baseFeat) {
97
        m_qgParent = m_vpp->getQGSPage()->findQViewForDocObj(m_baseFeat);
98
    }
99

100
    ui->setupUi(this);
101

102
    m_title = QObject::tr("Rich text editor");
103
    setUiEdit();
104

105
    m_attachPoint = Rez::guiX(Base::Vector3d(m_annoFeat->X.getValue(),
106
                                            -m_annoFeat->Y.getValue(),
107
                                             0.0));
108

109
    connect(ui->pbEditor, &QPushButton::clicked,
110
            this, &TaskRichAnno::onEditorClicked);
111
}
112

113
//ctor for creation
114
TaskRichAnno::TaskRichAnno(TechDraw::DrawView* baseFeat,
115
                           TechDraw::DrawPage* page) :
116
    ui(new Ui_TaskRichAnno),
117
    m_annoVP(nullptr),
118
    m_baseFeat(baseFeat),
119
    m_basePage(page),
120
    m_annoFeat(nullptr),
121
    m_qgParent(nullptr),
122
    m_createMode(true),
123
    m_inProgressLock(false),
124
    m_btnOK(nullptr),
125
    m_btnCancel(nullptr),
126
    m_textDialog(nullptr),
127
    m_rte(nullptr)
128
{
129
    //existence of baseFeat and page guaranteed by CmdTechDrawRichTextAnnotation (CommandAnnotate.cpp)
130
    Gui::Document* activeGui = Gui::Application::Instance->getDocument(m_basePage->getDocument());
131
    Gui::ViewProvider* vp = activeGui->getViewProvider(m_basePage);
132
    m_vpp = static_cast<ViewProviderPage*>(vp);
133

134
    m_qgParent = nullptr;
135
    if (m_vpp->getQGSPage()) {
136
        m_qgParent = m_vpp->getQGSPage()->findQViewForDocObj(baseFeat);
137
    }
138

139
    ui->setupUi(this);
140
    m_title = QObject::tr("Rich text creator");
141

142
    setUiPrimary();
143

144
    connect(ui->pbEditor, &QPushButton::clicked,
145
            this, &TaskRichAnno::onEditorClicked);
146
}
147

148
void TaskRichAnno::updateTask()
149
{
150
//    blockUpdate = true;
151

152
//    blockUpdate = false;
153
}
154

155
void TaskRichAnno::changeEvent(QEvent *event)
156
{
157
    if (event->type() == QEvent::LanguageChange) {
158
        ui->retranslateUi(this);
159
    }
160
}
161

162
void TaskRichAnno::setUiPrimary()
163
{
164
//    Base::Console().Message("TRA::setUiPrimary()\n");
165
    enableVPUi(false);
166
    setWindowTitle(m_title);
167

168
    if (m_baseFeat) {
169
        std::string baseName = m_baseFeat->getNameInDocument();
170
        ui->leBaseView->setText(Base::Tools::fromStdString(baseName));
171
    }
172
    ui->dsbWidth->setUnit(Base::Unit::Length);
173
    ui->dsbWidth->setMinimum(0);
174
    ui->dsbWidth->setValue(prefWeight());
175

176
    ui->cpFrameColor->setColor(prefLineColor().asValue<QColor>());
177
    // set a default font size, use for this the preferences setting
178
    MRichTextEdit mre;
179
    ui->teAnnoText->setFontPointSize(mre.getDefFontSizeNum());
180
    // set a placeholder text to inform the user
181
    ui->teAnnoText->setPlaceholderText(tr("Input the annotation text directly or start the rich text editor"));
182
}
183

184
void TaskRichAnno::enableTextUi(bool enable)
185
{
186
    ui->pbEditor->setEnabled(enable);
187
    ui->teAnnoText->setEnabled(enable);
188
}
189

190
//switch widgets related to ViewProvider on/off
191
//there is no ViewProvider until some time after feature is created.
192
void TaskRichAnno::enableVPUi(bool enable)
193
{
194
    Q_UNUSED(enable);
195
//    ui->cpLineColor->setEnabled(b);
196
//    ui->dsbWeight->setEnabled(b);
197
//    ui->cboxStyle->setEnabled(b);
198
}
199

200
void TaskRichAnno::setUiEdit()
201
{
202
//    Base::Console().Message("TRA::setUiEdit());
203
    enableVPUi(true);
204
    setWindowTitle(m_title);
205
    enableTextUi(true);
206

207
    if (m_annoFeat) {
208
        std::string baseName("None");
209
        App::DocumentObject* docObj = m_annoFeat->AnnoParent.getValue();
210
        if (docObj) {
211
            baseName = docObj->getNameInDocument();
212
        }
213
        ui->leBaseView->setText(Base::Tools::fromStdString(baseName));
214
        ui->teAnnoText->setHtml(QString::fromUtf8(m_annoFeat->AnnoText.getValue()));
215
        ui->dsbMaxWidth->setValue(m_annoFeat->MaxWidth.getValue());
216
        ui->cbShowFrame->setChecked(m_annoFeat->ShowFrame.getValue());
217
    }
218

219
    if (m_annoVP) {
220
        ui->cpFrameColor->setColor(m_annoVP->LineColor.getValue().asValue<QColor>());
221
        ui->dsbWidth->setValue(m_annoVP->LineWidth.getValue());
222
        ui->cFrameStyle->setCurrentIndex(m_annoVP->LineStyle.getValue());
223
    }
224
}
225

226
void TaskRichAnno::onEditorClicked(bool clicked)
227
{
228
//    Base::Console().Message("TL::onEditorClicked(%d)\n", b);
229
    Q_UNUSED(clicked);
230
    m_textDialog = new QDialog(nullptr);
231
    QString leadText = ui->teAnnoText->toHtml();
232
    QString plainText = ui->teAnnoText->toPlainText();
233
    if (plainText.isEmpty()) {
234
        m_rte = new MRichTextEdit(m_textDialog);
235
    } else {
236
        m_rte = new MRichTextEdit(m_textDialog, leadText);
237
    }
238
    QGridLayout* gl = new QGridLayout(m_textDialog);
239
    gl->addWidget(m_rte, 0,0, 1,1);
240
    m_textDialog->setWindowTitle(QObject::tr("Rich text editor"));
241
    m_textDialog->setMinimumWidth (400);
242
    m_textDialog->setMinimumHeight(400);
243

244
    connect(m_rte, &MRichTextEdit::saveText,
245
            this, &TaskRichAnno::onSaveAndExit);
246
    connect(m_rte, &MRichTextEdit::editorFinished,
247
            this, &TaskRichAnno::onEditorExit);
248

249
    m_textDialog->show();
250
}
251

252
void TaskRichAnno::onSaveAndExit(QString qs)
253
{
254
    ui->teAnnoText->setHtml(qs);
255
    //dialog clean up should be handled by accept() call in dialog
256
    m_textDialog->accept();
257
    m_textDialog = nullptr;
258
    m_rte = nullptr;
259
}
260

261
void TaskRichAnno::onEditorExit()
262
{
263
    m_textDialog->reject();
264
    m_textDialog = nullptr;
265
    m_rte = nullptr;
266
}
267

268
double TaskRichAnno::prefWeight() const
269
{
270
    return TechDraw::LineGroup::getDefaultWidth("Graphic");
271
}
272

273
App::Color TaskRichAnno::prefLineColor()
274
{
275
    return PreferencesGui::leaderColor();
276
}
277

278

279
//******************************************************************************
280
void TaskRichAnno::createAnnoFeature()
281
{
282
//    Base::Console().Message("TRA::createAnnoFeature()");
283
    const std::string objectName{QT_TR_NOOP("RichTextAnnotation")};
284
    std::string annoName = m_basePage->getDocument()->getUniqueObjectName(objectName.c_str());
285
    std::string generatedSuffix {annoName.substr(objectName.length())};
286
    std::string annoType = "TechDraw::DrawRichAnno";
287

288
    std::string PageName = m_basePage->getNameInDocument();
289

290
    Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Anno"));
291
    Command::doCommand(Command::Doc, "App.activeDocument().addObject('%s', '%s')",
292
                       annoType.c_str(), annoName.c_str());
293
    Command::doCommand(Command::Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)",
294
                       PageName.c_str(), annoName.c_str());
295

296
    if (m_baseFeat) {
297
        Command::doCommand(Command::Doc, "App.activeDocument().%s.AnnoParent = App.activeDocument().%s",
298
                               annoName.c_str(), m_baseFeat->getNameInDocument());
299
    }
300
    App::DocumentObject* obj = m_basePage->getDocument()->getObject(annoName.c_str());
301
    if (!obj) {
302
        throw Base::RuntimeError("TaskRichAnno - new RichAnno object not found");
303
    }
304
    if (obj->isDerivedFrom(TechDraw::DrawRichAnno::getClassTypeId())) {
305
        m_annoFeat = static_cast<TechDraw::DrawRichAnno*>(obj);
306
        commonFeatureUpdate();
307
        if (m_baseFeat) {
308
            QPointF qTemp = calcTextStartPos(m_annoFeat->getScale());
309
            Base::Vector3d vTemp(qTemp.x(), qTemp.y());
310
            m_annoFeat->X.setValue(Rez::appX(vTemp.x));
311
            m_annoFeat->Y.setValue(Rez::appX(vTemp.y));
312
        } else {
313
            //if we don't have a base feature, we can't calculate start position, so just put it mid-page
314
            m_annoFeat->X.setValue(m_basePage->getPageWidth()/2.0);
315
            m_annoFeat->Y.setValue(m_basePage->getPageHeight()/2.0);
316
        }
317
    }
318

319
    if (m_annoFeat) {
320
        Gui::ViewProvider* vp = QGIView::getViewProvider(m_annoFeat);
321
        auto annoVP = dynamic_cast<ViewProviderRichAnno*>(vp);
322
        if (annoVP) {
323
            App::Color ac;
324
            ac.setValue<QColor>(ui->cpFrameColor->color());
325
            annoVP->LineColor.setValue(ac);
326
            annoVP->LineWidth.setValue(ui->dsbWidth->rawValue());
327
            annoVP->LineStyle.setValue(ui->cFrameStyle->currentIndex());
328
        }
329
    }
330

331
    std::string translatedObjectName{tr(objectName.c_str()).toStdString()};
332
    obj->Label.setValue(translatedObjectName + generatedSuffix);
333

334
    Gui::Command::commitCommand();
335
    Gui::Command::updateActive();
336

337
    //trigger claimChildren in tree
338
    if (m_baseFeat) {
339
        m_baseFeat->touch();
340
    }
341

342
    m_basePage->touch();
343

344
    if (m_annoFeat) {
345
        m_annoFeat->requestPaint();
346
    }
347
}
348

349
void TaskRichAnno::updateAnnoFeature()
350
{
351
//    Base::Console().Message("TRA::updateAnnoFeature()\n");
352
    Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Edit Anno"));
353
    commonFeatureUpdate();
354
    App::Color ac;
355
    ac.setValue<QColor>(ui->cpFrameColor->color());
356
    m_annoVP->LineColor.setValue(ac);
357
    m_annoVP->LineWidth.setValue(ui->dsbWidth->rawValue());
358
    m_annoVP->LineStyle.setValue(ui->cFrameStyle->currentIndex());
359

360
    Gui::Command::commitCommand();
361
    Gui::Command::updateActive();
362
}
363

364
void TaskRichAnno::commonFeatureUpdate()
365
{
366
//    Base::Console().Message("TRA::commonFeatureUpdate()\n");
367
    m_annoFeat->setPosition(Rez::appX(m_attachPoint.x), Rez::appX(- m_attachPoint.y), true);
368
    m_annoFeat->AnnoText.setValue(ui->teAnnoText->toHtml().toUtf8());
369
    m_annoFeat->MaxWidth.setValue(ui->dsbMaxWidth->value().getValue());
370
    m_annoFeat->ShowFrame.setValue(ui->cbShowFrame->isChecked());
371
}
372

373
void TaskRichAnno::removeFeature()
374
{
375
//    Base::Console().Message("TRA::removeFeature()\n");
376
    if (!m_annoFeat)
377
        return;
378

379
    if (m_createMode) {
380
        try {
381
            // this doesn't remove the QGMText item??
382
            std::string PageName = m_basePage->getNameInDocument();
383
            Gui::Command::doCommand(Gui::Command::Gui, "App.activeDocument().%s.removeView(App.activeDocument().%s)",
384
                                    PageName.c_str(), m_annoFeat->getNameInDocument());
385
            Gui::Command::doCommand(Gui::Command::Gui, "App.activeDocument().removeObject('%s')",
386
                                        m_annoFeat->getNameInDocument());
387
        }
388
        catch (...) {
389
            Base::Console().Warning("TRA::removeFeature - failed to delete feature\n");
390
            return;
391
        }
392
    } else {
393
        if (Gui::Command::hasPendingCommand()) {
394
            std::vector<std::string> undos = Gui::Application::Instance->activeDocument()->getUndoVector();
395
            Gui::Application::Instance->activeDocument()->undo(1);
396
        }
397
    }
398
}
399

400
//we don't know the bounding rect of the text, so we have to calculate a reasonable
401
//guess at the size of the text block.
402
QPointF TaskRichAnno::calcTextStartPos(double scale)
403
{
404
    Q_UNUSED(scale)
405
//    Base::Console().Message("TRA::calcTextStartPos(%.3f)\n", scale);
406
    double textWidth = 100.0;
407
    double textHeight = 20.0;
408
    double horizGap(20.0);
409
    double tPosX(0.0);
410
    double tPosY(0.0);
411

412
    double width = m_annoFeat->MaxWidth.getValue();
413
    if (width > 0 ) {
414
        textWidth = width;
415
    }
416

417
    std::vector<Base::Vector3d> points;
418
    if (m_baseFeat) {
419
        if (m_baseFeat->isDerivedFrom(TechDraw::DrawLeaderLine::getClassTypeId())) {
420
            TechDraw::DrawLeaderLine* dll = static_cast<TechDraw::DrawLeaderLine*>(m_baseFeat);
421
            points = dll->WayPoints.getValues();
422
        } else {
423
//            Base::Console().Message("TRA::calcTextPos - m_baseFeat is not Leader\n");
424
            return QPointF(0.0, 0.0);
425
        }
426
    } else {
427
//        Base::Console().Message("TRA::calcStartPos - no m_baseFeat\n");
428
        if (m_basePage) {
429
            double w = Rez::guiX(m_basePage->getPageWidth() / 2.0);
430
            double h = Rez::guiX(m_basePage->getPageHeight() / 2.0);
431
            return QPointF(w, h);
432
        } else {
433
            Base::Console().Message("TRA::calcStartPos - no m_basePage\n"); //shouldn't happen. caught elsewhere
434
        }
435
    }
436

437
    if (!points.empty()) {
438
        QPointF lastPoint(points.back().x, points.back().y);
439
        QPointF firstPoint(points.front().x, points.front().y);
440
        QPointF lastOffset = lastPoint - firstPoint;
441

442
        if (lastPoint.x() < firstPoint.x()) {                 //last is left of first
443
            tPosX = lastOffset.x() - horizGap - textWidth;    //left of last
444
            tPosY = lastOffset.y() - textHeight;
445
        } else {                                             //last is right of first
446
            tPosX = lastOffset.x() + horizGap;               //right of last
447
            tPosY = lastOffset.y() - textHeight;
448
        }
449
    }
450
    return QPointF(tPosX, -tPosY);
451
}
452

453
void TaskRichAnno::saveButtons(QPushButton* btnOK,
454
                             QPushButton* btnCancel)
455
{
456
    m_btnOK = btnOK;
457
    m_btnCancel = btnCancel;
458
}
459

460
void TaskRichAnno::enableTaskButtons(bool enable)
461
{
462
    m_btnOK->setEnabled(enable);
463
    m_btnCancel->setEnabled(enable);
464
}
465

466
//******************************************************************************
467

468
bool TaskRichAnno::accept()
469
{
470
//    Base::Console().Message("TRA::accept()\n");
471
    if (m_inProgressLock) {
472
//        Base::Console().Message("TRA::accept - edit in progress!!\n");
473
        //TODO: kill MRTE dialog?
474
        return true;
475
    }
476

477
    Gui::Document* doc = Gui::Application::Instance->getDocument(m_basePage->getDocument());
478
    if (!doc)
479
        return false;
480

481
    if (getCreateMode())  {
482
        createAnnoFeature();
483
    } else {
484
        updateAnnoFeature();
485
    }
486

487
    m_annoFeat->requestPaint();
488

489
    Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()");
490

491
    return true;
492
}
493

494
bool TaskRichAnno::reject()
495
{
496
//    Base::Console().Message("TRA::reject()\n");
497
    if (m_inProgressLock) {
498
//        Base::Console().Message("TRA::reject - edit in progress!!\n");
499
        return false;
500
    }
501

502
    if (m_basePage) {
503
        Gui::Document* doc = Gui::Application::Instance->getDocument(m_basePage->getDocument());
504
        if (!doc) {
505
            return false;
506
        }
507
        if (getCreateMode() && m_annoFeat)  {
508
            removeFeature();
509
        }
510
    }
511

512
    //make sure any dangling objects are cleaned up
513
    Gui::Command::doCommand(Gui::Command::Gui, "App.activeDocument().recompute()");
514
    Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()");
515

516
    return false;
517
}
518

519
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
520
TaskDlgRichAnno::TaskDlgRichAnno(TechDraw::DrawView* baseFeat,
521
                                 TechDraw::DrawPage* page)
522
    : TaskDialog()
523
{
524
    widget  = new TaskRichAnno(baseFeat, page);
525
    taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/TechDraw_RichTextAnnotation"),
526
                                              widget->windowTitle(), true, nullptr);
527
    taskbox->groupLayout()->addWidget(widget);
528
    Content.push_back(taskbox);
529
}
530

531
TaskDlgRichAnno::TaskDlgRichAnno(TechDrawGui::ViewProviderRichAnno* annoVP)
532
    : TaskDialog()
533
{
534
    widget  = new TaskRichAnno(annoVP);
535
    taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/TechDraw_RichTextAnnotation"),
536
                                         widget->windowTitle(), true, nullptr);
537
    taskbox->groupLayout()->addWidget(widget);
538
    Content.push_back(taskbox);
539
}
540

541
TaskDlgRichAnno::~TaskDlgRichAnno()
542
{
543
}
544

545
void TaskDlgRichAnno::update()
546
{
547
//    widget->updateTask();
548
}
549

550
void TaskDlgRichAnno::modifyStandardButtons(QDialogButtonBox* box)
551
{
552
    QPushButton* btnOK = box->button(QDialogButtonBox::Ok);
553
    QPushButton* btnCancel = box->button(QDialogButtonBox::Cancel);
554
    widget->saveButtons(btnOK, btnCancel);
555
}
556

557
//==== calls from the TaskView ===============================================================
558
void TaskDlgRichAnno::open()
559
{
560
}
561

562
void TaskDlgRichAnno::clicked(int)
563
{
564
}
565

566
bool TaskDlgRichAnno::accept()
567
{
568
    widget->accept();
569
    return true;
570
}
571

572
bool TaskDlgRichAnno::reject()
573
{
574
    widget->reject();
575
    return true;
576
}
577

578
#include <Mod/TechDraw/Gui/moc_TaskRichAnno.cpp>
579

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

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

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

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