Files
create/src/Mod/TechDraw/Gui/QGIRichAnno.cpp
wmayer 97330443a2 All: modernize C++11
* replace deprecated headers
2022-03-23 22:44:18 +01:00

398 lines
12 KiB
C++

/***************************************************************************
* Copyright (c) 2019 WandererFan <wandererfan@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <BRep_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <Precision.hxx>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsItem>
#include <QPainter>
#include <QPainterPath>
#include <QPaintDevice>
#include <QSvgGenerator>
#include <QRegExp>
#include <QTextDocument>
#include <QTextDocumentFragment>
#include <QTextFrame>
#include <QTextBlock>
#include <QTextCursor>
#include <QDialog>
# include <cmath>
#endif
#include <App/Application.h>
#include <App/Material.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Parameter.h>
#include <Base/Tools.h>
#include <Base/UnitsApi.h>
#include <Gui/Command.h>
#include <Mod/Part/App/PartFeature.h>
//#include <Mod/TechDraw/App/Preferences.h>
#include <Mod/TechDraw/App/DrawRichAnno.h>
#include <Mod/TechDraw/App/DrawUtil.h>
#include <Mod/TechDraw/App/Geometry.h>
#include "Rez.h"
#include "ZVALUE.h"
#include "PreferencesGui.h"
#include "QGIArrow.h"
#include "ViewProviderRichAnno.h"
#include "MDIViewPage.h"
#include "DrawGuiUtil.h"
#include "QGVPage.h"
#include "QGIPrimPath.h"
#include "QGEPath.h"
#include "QGMText.h"
#include "QGIView.h"
#include "QGCustomText.h"
#include "QGCustomRect.h"
#include "QGIRichAnno.h"
#include "mrichtextedit.h"
using namespace TechDraw;
using namespace TechDrawGui;
//**************************************************************
QGIRichAnno::QGIRichAnno(QGraphicsItem* myParent,
TechDraw::DrawRichAnno* anno) :
m_isExporting(false), m_hasHover(false)
{
setHandlesChildEvents(false);
setAcceptHoverEvents(false);
setFlag(QGraphicsItem::ItemIsSelectable, true);
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
setFlag(QGraphicsItem::ItemSendsGeometryChanges,true);
if (myParent != nullptr) {
setParentItem(myParent);
}
setViewFeature(anno);
m_text = new QGCustomText();
m_text->setTextInteractionFlags(Qt::NoTextInteraction);
addToGroup(m_text);
m_text->setZValue(ZVALUE::DIMENSION);
m_text->centerAt(0.0, 0.0);
m_rect = new QGCustomRect();
addToGroup(m_rect);
m_rect->setZValue(ZVALUE::DIMENSION - 1);
m_rect->centerAt(0.0, 0.0);
setZValue(ZVALUE::DIMENSION);
}
QVariant QGIRichAnno::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemSelectedHasChanged && scene()) {
//There's nothing special for QGIRA to do when selection changes!
} else if(change == ItemSceneChange && scene()) {
// nothing special!
}
return QGIView::itemChange(change, value);
}
//void QGIRichAnno::select(bool state)
//{
// setSelected(state);
// draw();
//}
//void QGIRichAnno::hover(bool state)
//{
// m_hasHover = state;
// draw();
//}
void QGIRichAnno::updateView(bool update)
{
// Base::Console().Message("QGIRA::updateView() - %s\n", getViewName());
Q_UNUSED(update);
auto annoFeat( dynamic_cast<TechDraw::DrawRichAnno*>(getViewObject()) );
if ( annoFeat == nullptr ) {
Base::Console().Log("QGIRA::updateView - no feature!\n");
return;
}
auto vp = static_cast<ViewProviderRichAnno*>(getViewProvider(getViewObject()));
if ( vp == nullptr ) {
return;
}
if (annoFeat->X.isTouched() ||
annoFeat->Y.isTouched()) {
float x = Rez::guiX(annoFeat->X.getValue());
float y = Rez::guiX(annoFeat->Y.getValue());
m_text->centerAt(x, -y);
m_rect->centerAt(x, -y);
}
draw();
}
void QGIRichAnno::drawBorder()
{
////Leaders have no border!
// QGIView::drawBorder(); //good for debugging
}
void QGIRichAnno::draw()
{
// Base::Console().Log("QGIRA::draw() - %s - parent: %X\n",getFeature()->getNameInDocument(), parentItem());
if (!isVisible()) {
// Base::Console().Message("QGIRA::draw - not visible\n");
return;
}
TechDraw::DrawRichAnno* annoFeat = getFeature();
if((!annoFeat) ) {
// Base::Console().Message("QGIRA::draw - no feature\n");
return;
}
auto vp = static_cast<ViewProviderRichAnno*>(getViewProvider(getFeature()));
if ( vp == nullptr ) {
// Base::Console().Message("QGIRA::draw - no viewprovider\n");
return;
}
// double appX = Rez::guiX(annoFeat->X.getValue());
// double appY = Rez::guiX(annoFeat->Y.getValue());
QGIView::draw();
setTextItem();
}
void QGIRichAnno::setTextItem()
{
// Base::Console().Message("QGIRA::setTextItem() - %s\n",getViewName());
TechDraw::DrawRichAnno* annoFeat = getFeature();
QString inHtml = QString::fromUtf8(annoFeat->AnnoText.getValue());
//don't do this multiplication if exporting to SVG as other apps interpret
//font sizes differently from QGraphicsTextItem (?)
if (!getExporting()) {
//convert point font sizes to (Rez,mm) font sizes
QRegExp rxFontSize(QString::fromUtf8("font-size:([0-9]*)pt;"));
QString match;
double mmPerPoint = 0.353;
double sizeConvert = Rez::getRezFactor() * mmPerPoint;
int pos = 0;
QStringList findList;
QStringList replList;
while ((pos = rxFontSize.indexIn(inHtml, pos)) != -1) {
QString found = rxFontSize.cap(0);
findList << found;
QString qsOldSize = rxFontSize.cap(1);
QString repl = found;
double newSize = qsOldSize.toDouble();
newSize = newSize * sizeConvert;
QString qsNewSize = QString::number(newSize, 'f', 2);
repl.replace(qsOldSize,qsNewSize);
replList << repl;
pos += rxFontSize.matchedLength();
}
QString outHtml = inHtml;
int iRepl = 0;
//TODO: check list for duplicates?
for ( ; iRepl < findList.size(); iRepl++) {
outHtml = outHtml.replace(findList[iRepl], replList[iRepl]);
}
m_text->setTextWidth(Rez::guiX(annoFeat->MaxWidth.getValue()));
m_text->setHtml(outHtml);
// setLineSpacing(50); //this has no effect on the display?!
// m_text->update();
if (annoFeat->ShowFrame.getValue()) {
QRectF r = m_text->boundingRect().adjusted(1,1,-1,-1);
m_rect->setPen(rectPen());
m_rect->setBrush(Qt::NoBrush);
m_rect->setRect(r);
m_rect->show();
} else {
m_rect->hide();
}
} else {
// don't force line wrap & strip formatting that doesn't export well!
double realWidth = m_text->boundingRect().width();
m_text->setTextWidth(realWidth);
QFont f = prefFont();
double ptSize = prefPointSize();
f.setPointSizeF(ptSize);
m_text->setFont(f);
QString plainText = QTextDocumentFragment::fromHtml( inHtml ).toPlainText();
m_text->setPlainText(plainText);
setLineSpacing(100); //this doesn't appear in the generated Svg, but does space the lines!
m_rect->hide();
m_rect->update();
}
m_text->centerAt(0.0, 0.0);
m_rect->centerAt(0.0, 0.0);
}
void QGIRichAnno::setLineSpacing(int lineSpacing)
{
//this line spacing should be px, but seems to be %? in any event, it does
//space out the lines.
QTextBlock block = m_text->document()->begin();
for (; block.isValid(); block = block.next()) {
QTextCursor tc = QTextCursor(block);
QTextBlockFormat fmt = block.blockFormat();
// fmt.setTopMargin(lineSpacing); //no effect???
fmt.setBottomMargin(lineSpacing); //spaces out the lines!
tc.setBlockFormat(fmt);
// }
}
}
//void QGIRichAnno::drawBorder()
//{
//////Leaders have no border!
//// QGIView::drawBorder(); //good for debugging
//}
TechDraw::DrawRichAnno* QGIRichAnno::getFeature(void)
{
TechDraw::DrawRichAnno* result =
static_cast<TechDraw::DrawRichAnno*>(getViewObject());
return result;
}
QRectF QGIRichAnno::boundingRect() const
{
QRectF rect = mapFromItem(m_text,m_text->boundingRect()).boundingRect();
return rect.adjusted(-10.,-10.,10.,10.);
}
QPainterPath QGIRichAnno::shape() const
{
return QGraphicsItemGroup::shape();
}
void QGIRichAnno::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) {
QStyleOptionGraphicsItem myOption(*option);
myOption.state &= ~QStyle::State_Selected;
// painter->drawRect(boundingRect()); //good for debugging
QGIView::paint (painter, &myOption, widget);
}
QPen QGIRichAnno::rectPen() const
{
QPen pen;
const auto sym( dynamic_cast<TechDraw::DrawRichAnno*>(getViewObject()) );
if( sym == nullptr ) {
return pen;
}
auto vp = static_cast<ViewProviderRichAnno*>(getViewProvider(getViewObject()));
if ( vp == nullptr ) {
return pen;
}
double rectWeight = Rez::guiX(vp->LineWidth.getValue());
Qt::PenStyle rectStyle = (Qt::PenStyle) vp->LineStyle.getValue();
App::Color temp = vp->LineColor.getValue();
QColor rectColor = temp.asValue<QColor>();
pen = QPen(rectStyle);
pen.setWidthF(rectWeight);
pen.setColor(rectColor);
return pen;
}
QFont QGIRichAnno::prefFont(void)
{
return PreferencesGui::labelFontQFont();
}
double QGIRichAnno::prefPointSize(void)
{
// Base::Console().Message("QGIRA::prefPointSize()\n");
double fontSize = Preferences::dimFontSizeMM();
//this conversion is only approximate. the factor changes for different fonts.
// double mmToPts = 2.83; //theoretical value
double mmToPts = 2.00; //practical value. seems to be reasonable for common fonts.
double ptsSize = round(fontSize * mmToPts);
return ptsSize;
}
void QGIRichAnno::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) {
Q_UNUSED(event);
TechDraw::DrawRichAnno *annotation = dynamic_cast<TechDraw::DrawRichAnno *>(getViewObject());
if (annotation == nullptr) {
return;
}
QString text = QString::fromUtf8(annotation->AnnoText.getValue());
QDialog dialog(nullptr);
dialog.setWindowTitle(QObject::tr("Rich text editor"));
dialog.setMinimumWidth(400);
dialog.setMinimumHeight(400);
MRichTextEdit richEdit(&dialog, text);
QGridLayout gridLayout(&dialog);
gridLayout.addWidget(&richEdit, 0, 0, 1, 1);
connect(&richEdit, SIGNAL(saveText(QString)), &dialog, SLOT(accept()));
connect(&richEdit, SIGNAL(editorFinished(void)), &dialog, SLOT(reject()));
if (dialog.exec()) {
QString newText = richEdit.toHtml();
if (newText != text) {
App::GetApplication().setActiveTransaction("Set Rich Annotation Text");
annotation->AnnoText.setValue(newText.toStdString());
App::GetApplication().closeActiveTransaction();
}
}
}
#include <Mod/TechDraw/Gui/moc_QGIRichAnno.cpp>