1
/***************************************************************************
2
* Copyright (c) 2019 WandererFan <wandererfan@gmail.com> *
4
* This file is part of the FreeCAD CAx development system. *
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. *
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. *
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 *
21
***************************************************************************/
23
#include "PreCompiled.h"
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>
42
#include "ui_TaskRichAnno.h"
43
#include "TaskRichAnno.h"
44
#include "mrichtextedit.h"
45
#include "PreferencesGui.h"
50
#include "ViewProviderPage.h"
51
#include "ViewProviderRichAnno.h"
55
using namespace TechDraw;
56
using namespace TechDrawGui;
59
TaskRichAnno::TaskRichAnno(TechDrawGui::ViewProviderRichAnno* annoVP) :
60
ui(new Ui_TaskRichAnno),
67
m_inProgressLock(false),
70
m_textDialog(nullptr),
73
//existence of annoVP is guaranteed by caller being ViewProviderRichAnno.setEdit
75
m_annoFeat = m_annoVP->getFeature();
77
m_basePage = m_annoFeat->findParentPage();
79
Base::Console().Error("TaskRichAnno - bad parameters (2). Can not proceed.\n");
83
//m_baseFeat can be null
84
App::DocumentObject* obj = m_annoFeat->AnnoParent.getValue();
86
if ( obj->isDerivedFrom(TechDraw::DrawView::getClassTypeId()) ) {
87
m_baseFeat = static_cast<TechDraw::DrawView*>(m_annoFeat->AnnoParent.getValue());
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);
97
m_qgParent = m_vpp->getQGSPage()->findQViewForDocObj(m_baseFeat);
102
m_title = QObject::tr("Rich text editor");
105
m_attachPoint = Rez::guiX(Base::Vector3d(m_annoFeat->X.getValue(),
106
-m_annoFeat->Y.getValue(),
109
connect(ui->pbEditor, &QPushButton::clicked,
110
this, &TaskRichAnno::onEditorClicked);
114
TaskRichAnno::TaskRichAnno(TechDraw::DrawView* baseFeat,
115
TechDraw::DrawPage* page) :
116
ui(new Ui_TaskRichAnno),
118
m_baseFeat(baseFeat),
123
m_inProgressLock(false),
125
m_btnCancel(nullptr),
126
m_textDialog(nullptr),
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);
134
m_qgParent = nullptr;
135
if (m_vpp->getQGSPage()) {
136
m_qgParent = m_vpp->getQGSPage()->findQViewForDocObj(baseFeat);
140
m_title = QObject::tr("Rich text creator");
144
connect(ui->pbEditor, &QPushButton::clicked,
145
this, &TaskRichAnno::onEditorClicked);
148
void TaskRichAnno::updateTask()
150
// blockUpdate = true;
152
// blockUpdate = false;
155
void TaskRichAnno::changeEvent(QEvent *event)
157
if (event->type() == QEvent::LanguageChange) {
158
ui->retranslateUi(this);
162
void TaskRichAnno::setUiPrimary()
164
// Base::Console().Message("TRA::setUiPrimary()\n");
166
setWindowTitle(m_title);
169
std::string baseName = m_baseFeat->getNameInDocument();
170
ui->leBaseView->setText(Base::Tools::fromStdString(baseName));
172
ui->dsbWidth->setUnit(Base::Unit::Length);
173
ui->dsbWidth->setMinimum(0);
174
ui->dsbWidth->setValue(prefWeight());
176
ui->cpFrameColor->setColor(prefLineColor().asValue<QColor>());
177
// set a default font size, use for this the preferences setting
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"));
184
void TaskRichAnno::enableTextUi(bool enable)
186
ui->pbEditor->setEnabled(enable);
187
ui->teAnnoText->setEnabled(enable);
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)
195
// ui->cpLineColor->setEnabled(b);
196
// ui->dsbWeight->setEnabled(b);
197
// ui->cboxStyle->setEnabled(b);
200
void TaskRichAnno::setUiEdit()
202
// Base::Console().Message("TRA::setUiEdit());
204
setWindowTitle(m_title);
208
std::string baseName("None");
209
App::DocumentObject* docObj = m_annoFeat->AnnoParent.getValue();
211
baseName = docObj->getNameInDocument();
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());
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());
226
void TaskRichAnno::onEditorClicked(bool clicked)
228
// Base::Console().Message("TL::onEditorClicked(%d)\n", b);
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);
236
m_rte = new MRichTextEdit(m_textDialog, leadText);
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);
244
connect(m_rte, &MRichTextEdit::saveText,
245
this, &TaskRichAnno::onSaveAndExit);
246
connect(m_rte, &MRichTextEdit::editorFinished,
247
this, &TaskRichAnno::onEditorExit);
249
m_textDialog->show();
252
void TaskRichAnno::onSaveAndExit(QString qs)
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;
261
void TaskRichAnno::onEditorExit()
263
m_textDialog->reject();
264
m_textDialog = nullptr;
268
double TaskRichAnno::prefWeight() const
270
return TechDraw::LineGroup::getDefaultWidth("Graphic");
273
App::Color TaskRichAnno::prefLineColor()
275
return PreferencesGui::leaderColor();
279
//******************************************************************************
280
void TaskRichAnno::createAnnoFeature()
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";
288
std::string PageName = m_basePage->getNameInDocument();
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());
297
Command::doCommand(Command::Doc, "App.activeDocument().%s.AnnoParent = App.activeDocument().%s",
298
annoName.c_str(), m_baseFeat->getNameInDocument());
300
App::DocumentObject* obj = m_basePage->getDocument()->getObject(annoName.c_str());
302
throw Base::RuntimeError("TaskRichAnno - new RichAnno object not found");
304
if (obj->isDerivedFrom(TechDraw::DrawRichAnno::getClassTypeId())) {
305
m_annoFeat = static_cast<TechDraw::DrawRichAnno*>(obj);
306
commonFeatureUpdate();
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));
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);
320
Gui::ViewProvider* vp = QGIView::getViewProvider(m_annoFeat);
321
auto annoVP = dynamic_cast<ViewProviderRichAnno*>(vp);
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());
331
std::string translatedObjectName{tr(objectName.c_str()).toStdString()};
332
obj->Label.setValue(translatedObjectName + generatedSuffix);
334
Gui::Command::commitCommand();
335
Gui::Command::updateActive();
337
//trigger claimChildren in tree
345
m_annoFeat->requestPaint();
349
void TaskRichAnno::updateAnnoFeature()
351
// Base::Console().Message("TRA::updateAnnoFeature()\n");
352
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Edit Anno"));
353
commonFeatureUpdate();
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());
360
Gui::Command::commitCommand();
361
Gui::Command::updateActive();
364
void TaskRichAnno::commonFeatureUpdate()
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());
373
void TaskRichAnno::removeFeature()
375
// Base::Console().Message("TRA::removeFeature()\n");
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());
389
Base::Console().Warning("TRA::removeFeature - failed to delete feature\n");
393
if (Gui::Command::hasPendingCommand()) {
394
std::vector<std::string> undos = Gui::Application::Instance->activeDocument()->getUndoVector();
395
Gui::Application::Instance->activeDocument()->undo(1);
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)
405
// Base::Console().Message("TRA::calcTextStartPos(%.3f)\n", scale);
406
double textWidth = 100.0;
407
double textHeight = 20.0;
408
double horizGap(20.0);
412
double width = m_annoFeat->MaxWidth.getValue();
417
std::vector<Base::Vector3d> points;
419
if (m_baseFeat->isDerivedFrom(TechDraw::DrawLeaderLine::getClassTypeId())) {
420
TechDraw::DrawLeaderLine* dll = static_cast<TechDraw::DrawLeaderLine*>(m_baseFeat);
421
points = dll->WayPoints.getValues();
423
// Base::Console().Message("TRA::calcTextPos - m_baseFeat is not Leader\n");
424
return QPointF(0.0, 0.0);
427
// Base::Console().Message("TRA::calcStartPos - no m_baseFeat\n");
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);
433
Base::Console().Message("TRA::calcStartPos - no m_basePage\n"); //shouldn't happen. caught elsewhere
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;
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;
450
return QPointF(tPosX, -tPosY);
453
void TaskRichAnno::saveButtons(QPushButton* btnOK,
454
QPushButton* btnCancel)
457
m_btnCancel = btnCancel;
460
void TaskRichAnno::enableTaskButtons(bool enable)
462
m_btnOK->setEnabled(enable);
463
m_btnCancel->setEnabled(enable);
466
//******************************************************************************
468
bool TaskRichAnno::accept()
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?
477
Gui::Document* doc = Gui::Application::Instance->getDocument(m_basePage->getDocument());
481
if (getCreateMode()) {
487
m_annoFeat->requestPaint();
489
Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()");
494
bool TaskRichAnno::reject()
496
// Base::Console().Message("TRA::reject()\n");
497
if (m_inProgressLock) {
498
// Base::Console().Message("TRA::reject - edit in progress!!\n");
503
Gui::Document* doc = Gui::Application::Instance->getDocument(m_basePage->getDocument());
507
if (getCreateMode() && m_annoFeat) {
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()");
519
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
520
TaskDlgRichAnno::TaskDlgRichAnno(TechDraw::DrawView* baseFeat,
521
TechDraw::DrawPage* page)
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);
531
TaskDlgRichAnno::TaskDlgRichAnno(TechDrawGui::ViewProviderRichAnno* annoVP)
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);
541
TaskDlgRichAnno::~TaskDlgRichAnno()
545
void TaskDlgRichAnno::update()
547
// widget->updateTask();
550
void TaskDlgRichAnno::modifyStandardButtons(QDialogButtonBox* box)
552
QPushButton* btnOK = box->button(QDialogButtonBox::Ok);
553
QPushButton* btnCancel = box->button(QDialogButtonBox::Cancel);
554
widget->saveButtons(btnOK, btnCancel);
557
//==== calls from the TaskView ===============================================================
558
void TaskDlgRichAnno::open()
562
void TaskDlgRichAnno::clicked(int)
566
bool TaskDlgRichAnno::accept()
572
bool TaskDlgRichAnno::reject()
578
#include <Mod/TechDraw/Gui/moc_TaskRichAnno.cpp>