diff --git a/src/app/valentina/mainwindowsnogui.cpp b/src/app/valentina/mainwindowsnogui.cpp index f24b0b555..fb21b46ba 100644 --- a/src/app/valentina/mainwindowsnogui.cpp +++ b/src/app/valentina/mainwindowsnogui.cpp @@ -805,6 +805,7 @@ void MainWindowsNoGUI::DxfFile(const QString &name, int version, bool binary, in QGraphicsRectItem *paper = qgraphicsitem_cast(papers.at(i)); if (paper) { + PrepareTextForDXF(endStringPlaceholder); VDxfPaintDevice generator; generator.setFileName(name); generator.setSize(paper->rect().size().toSize()); @@ -835,6 +836,7 @@ void MainWindowsNoGUI::DxfFile(const QString &name, int version, bool binary, in scenes.at(i)->render(&painter, paper->rect(), paper->rect(), Qt::IgnoreAspectRatio); painter.end(); } + RestoreTextAfterDXF(endStringPlaceholder); } } @@ -868,6 +870,72 @@ void MainWindowsNoGUI::RestorePaper(int index) const } } +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief PrepareTextForDXF prepare QGraphicsSimpleTextItem items for export to flat dxf. + * + * Because QPaintEngine::drawTextItem doesn't pass whole string per time we mark end of each string by adding special + * placholder. This method append it. + * + * @param placeholder placeholder that will be appended to each QGraphicsSimpleTextItem item's text string. + */ +void MainWindowsNoGUI::PrepareTextForDXF(const QString &placeholder) const +{ + for (int i = 0; i < details.size(); ++i) + { + const QList &paperItems = details.at(i); + for (int j = 0; j < paperItems.size(); ++j) + { + QList pieceChildren = paperItems.at(i)->childItems(); + for (int k = 0; k < pieceChildren.size(); ++k) + { + QGraphicsItem *item = pieceChildren.at(k); + if (item->type() == QGraphicsSimpleTextItem::Type) + { + if(QGraphicsSimpleTextItem *textItem = qgraphicsitem_cast(item)) + { + textItem->setText(textItem->text() + placeholder); + } + } + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief MainWindowsNoGUI::RestoreTextAfterDXF restore QGraphicsSimpleTextItem items after export to flat dxf. + * + * Because QPaintEngine::drawTextItem doesn't pass whole string per time we mark end of each string by adding special + * placholder. This method remove it. + * + * @param placeholder placeholder that will be removed from each QGraphicsSimpleTextItem item's text string. + */ +void MainWindowsNoGUI::RestoreTextAfterDXF(const QString &placeholder) const +{ + for (int i = 0; i < details.size(); ++i) + { + const QList &paperItems = details.at(i); + for (int j = 0; j < paperItems.size(); ++j) + { + QList pieceChildren = paperItems.at(i)->childItems(); + for (int k = 0; k < pieceChildren.size(); ++k) + { + QGraphicsItem *item = pieceChildren.at(k); + if (item->type() == QGraphicsSimpleTextItem::Type) + { + if(QGraphicsSimpleTextItem *textItem = qgraphicsitem_cast(item)) + { + QString text = textItem->text(); + text.replace(placeholder, ""); + textItem->setText(text); + } + } + } + } + } +} + //--------------------------------------------------------------------------------------------------------------------- void MainWindowsNoGUI::SaveLayoutAs() { diff --git a/src/app/valentina/mainwindowsnogui.h b/src/app/valentina/mainwindowsnogui.h index 95cdbbafd..c5406318a 100644 --- a/src/app/valentina/mainwindowsnogui.h +++ b/src/app/valentina/mainwindowsnogui.h @@ -125,6 +125,9 @@ private: void PreparePaper(int index) const; void RestorePaper(int index) const; + void PrepareTextForDXF(const QString &placeholder) const; + void RestoreTextAfterDXF(const QString &placeholder) const; + void SaveLayoutAs(); void PrintPreview(); void LayoutPrint(); diff --git a/src/libs/vdxf/dxfdef.cpp b/src/libs/vdxf/dxfdef.cpp new file mode 100644 index 000000000..b2379ebcf --- /dev/null +++ b/src/libs/vdxf/dxfdef.cpp @@ -0,0 +1,33 @@ +/************************************************************************ + ** + ** @file + ** @author Roman Telezhynskyi + ** @date 29 6, 2017 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2017 Valentina project + ** All Rights Reserved. + ** + ** Valentina is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with Valentina. If not, see . + ** + *************************************************************************/ + +#include "dxfdef.h" + +#include + +const QString endStringPlaceholder = QStringLiteral("%&?_?&%"); diff --git a/src/libs/vdxf/dxfdef.h b/src/libs/vdxf/dxfdef.h index c62eb0f11..3ba500c56 100644 --- a/src/libs/vdxf/dxfdef.h +++ b/src/libs/vdxf/dxfdef.h @@ -1,6 +1,6 @@ /************************************************************************ ** - ** @file def.h + ** @file dxfdef.h ** @author Roman Telezhynskyi ** @date 31 8, 2015 ** @@ -40,6 +40,9 @@ enum class VarMeasurement : unsigned char { English=0, Metric=1 }; //Default drawing units for AutoCAD DesignCenter blocks: enum class VarInsunits : unsigned char { Inches=1, Millimeters=4, Centimeters=5 }; +// Helps mark end of string. See VDxfEngine::drawTextItem for more details +extern const QString endStringPlaceholder; + static inline bool DL_FuzzyComparePossibleNulls(double p1, double p2) Q_REQUIRED_RESULT; static inline bool DL_FuzzyComparePossibleNulls(double p1, double p2) { diff --git a/src/libs/vdxf/dxiface.cpp b/src/libs/vdxf/dxiface.cpp index 2a76675cd..aee5f8223 100644 --- a/src/libs/vdxf/dxiface.cpp +++ b/src/libs/vdxf/dxiface.cpp @@ -13,14 +13,18 @@ #include "dxiface.h" #include "libdxfrw/libdwgr.h" #include "libdxfrw/libdxfrw.h" +#include "../vmisc/vabstractapplication.h" #include #include #include +#include +#include -dx_iface::dx_iface(const std::string &file, VarMeasurement varMeasurement, VarInsunits varInsunits) +dx_iface::dx_iface(const std::string &file, DRW::Version v, VarMeasurement varMeasurement, VarInsunits varInsunits) : dxfW(new dxfRW(file.c_str())), - cData() + cData(), + version(v) { InitHeader(varMeasurement, varInsunits); InitLTypes(); @@ -34,9 +38,9 @@ dx_iface::~dx_iface() delete dxfW; } -bool dx_iface::fileExport(DRW::Version v, bool binary) +bool dx_iface::fileExport(bool binary) { - bool success = dxfW->write(this, v, binary); + bool success = dxfW->write(this, version, binary); return success; } @@ -179,6 +183,15 @@ void dx_iface::InitHeader(VarMeasurement varMeasurement, VarInsunits varInsunits QString dateTime = QDateTime::currentDateTime().toString("yyyyMMdd.HHmmsszzz"); dateTime.chop(1);// we need hundredths of a second cData.headerC.addStr("$TDCREATE", dateTime.toStdString(), 40); + + if (version >= DRW::AC1021) + { // Full support Unicode + cData.headerC.addStr("$DWGCODEPAGE", "UTF-8", 3); + } + else + { + cData.headerC.addStr("$DWGCODEPAGE", LocaleToISO(), 3); + } } void dx_iface::InitLTypes() @@ -264,3 +277,158 @@ void dx_iface::AddEntity(DRW_Entity *e) { cData.mBlock->ent.push_back(e); } + +UTF8STRING dx_iface::AddFont(const QFont &f) +{ + DRW_Textstyle ts; + ts.name = f.family().toStdString(); + + // Idea source https://stackoverflow.com/questions/20111522/writing-text-styles-into-dxf-from-a-delphi-application + if (f.bold()) + { + ts.name += "_BOLD"; + ts.fontFamily += 0x2000000; + } + + if (f.italic()) + { + ts.name += "_ITALIC"; + ts.fontFamily += 0x1000000; + } + + for (auto it = cData.textStyles.begin() ; it !=cData.textStyles.end() ; ++it) + { + if ((*it).name == ts.name) + { + return ts.name; + } + } + + ts.font = "Times New Roman";//f.family().toStdString(); + + cData.textStyles.push_back(ts); + + return ts.name; +} + +std::string dx_iface::LocaleToISO() const +{ + QMap locMap; + locMap["croatian"] = "ISO8859-2"; + locMap["cs"] = "ISO8859-2"; + locMap["cs_CS"] = "ISO8859-2"; + locMap["cs_CZ"] = "ISO8859-2"; + locMap["cz"] = "ISO8859-2"; + locMap["cz_CZ"] = "ISO8859-2"; + locMap["czech"] = "ISO8859-2"; + locMap["hr"] = "ISO8859-2"; + locMap["hr_HR"] = "ISO8859-2"; + locMap["hu"] = "ISO8859-2"; + locMap["hu_HU"] = "ISO8859-2"; + locMap["hungarian"] = "ISO8859-2"; + locMap["pl"] = "ISO8859-2"; + locMap["pl_PL"] = "ISO8859-2"; + locMap["polish"] = "ISO8859-2"; + locMap["ro"] = "ISO8859-2"; + locMap["ro_RO"] = "ISO8859-2"; + locMap["rumanian"] = "ISO8859-2"; + locMap["serbocroatian"] = "ISO8859-2"; + locMap["sh"] = "ISO8859-2"; + locMap["sh_SP"] = "ISO8859-2"; + locMap["sh_YU"] = "ISO8859-2"; + locMap["sk"] = "ISO8859-2"; + locMap["sk_SK"] = "ISO8859-2"; + locMap["sl"] = "ISO8859-2"; + locMap["sl_CS"] = "ISO8859-2"; + locMap["sl_SI"] = "ISO8859-2"; + locMap["slovak"] = "ISO8859-2"; + locMap["slovene"] = "ISO8859-2"; + locMap["sr_SP"] = "ISO8859-2"; + + locMap["eo"] = "ISO8859-3"; + + locMap["ee"] = "ISO8859-4"; + locMap["ee_EE"] = "ISO8859-4"; + + locMap["mk"] = "ISO8859-5"; + locMap["mk_MK"] = "ISO8859-5"; + locMap["sp"] = "ISO8859-5"; + locMap["sp_YU"] = "ISO8859-5"; + + locMap["ar_AA"] = "ISO8859-6"; + locMap["ar_SA"] = "ISO8859-6"; + locMap["arabic"] = "ISO8859-6"; + + locMap["el"] = "ISO8859-7"; + locMap["el_GR"] = "ISO8859-7"; + locMap["greek"] = "ISO8859-7"; + + locMap["hebrew"] = "ISO8859-8"; + locMap["he"] = "ISO8859-8"; + locMap["he_IL"] = "ISO8859-8"; + locMap["iw"] = "ISO8859-8"; + locMap["iw_IL"] = "ISO8859-8"; + + locMap["tr"] = "ISO8859-9"; + locMap["tr_TR"] = "ISO8859-9"; + locMap["turkish"] = "ISO8859-9"; + + locMap["lt"] = "ISO8859-13"; + locMap["lt_LT"] = "ISO8859-13"; + locMap["lv"] = "ISO8859-13"; + locMap["lv_LV"] = "ISO8859-13"; + + locMap["et"] = "ISO8859-15"; + locMap["et_EE"] = "ISO8859-15"; + locMap["br_FR"] = "ISO8859-15"; + locMap["ca_ES"] = "ISO8859-15"; + locMap["de"] = "ISO8859-15"; + locMap["de_AT"] = "ISO8859-15"; + locMap["de_BE"] = "ISO8859-15"; + locMap["de_DE"] = "ISO8859-15"; + locMap["de_LU"] = "ISO8859-15"; + locMap["en_IE"] = "ISO8859-15"; + locMap["es"] = "ISO8859-15"; + locMap["es_ES"] = "ISO8859-15"; + locMap["eu_ES"] = "ISO8859-15"; + locMap["fi"] = "ISO8859-15"; + locMap["fi_FI"] = "ISO8859-15"; + locMap["finnish"] = "ISO8859-15"; + locMap["fr"] = "ISO8859-15"; + locMap["fr_FR"] = "ISO8859-15"; + locMap["fr_BE"] = "ISO8859-15"; + locMap["fr_LU"] = "ISO8859-15"; + locMap["french"] = "ISO8859-15"; + locMap["ga_IE"] = "ISO8859-15"; + locMap["gl_ES"] = "ISO8859-15"; + locMap["it"] = "ISO8859-15"; + locMap["it_IT"] = "ISO8859-15"; + locMap["oc_FR"] = "ISO8859-15"; + locMap["nl"] = "ISO8859-15"; + locMap["nl_BE"] = "ISO8859-15"; + locMap["nl_NL"] = "ISO8859-15"; + locMap["pt"] = "ISO8859-15"; + locMap["pt_PT"] = "ISO8859-15"; + locMap["sv_FI"] = "ISO8859-15"; + locMap["wa_BE"] = "ISO8859-15"; + + locMap["uk"] = "KOI8-U"; + locMap["uk_UA"] = "KOI8-U"; + locMap["ru_YA"] = "KOI8-U"; + locMap["ukrainian"] = "KOI8-U"; + locMap["ru_RU"] = "KOI8-U"; + + locMap["be"] = "KOI8-R"; + locMap["be_BY"] = "KOI8-R"; + locMap["bg"] = "KOI8-R"; + locMap["bg_BG"] = "KOI8-R"; + locMap["bulgarian"] = "KOI8-R"; + locMap["ba_RU"] = "KOI8-R"; + locMap["ky"] = "KOI8-R"; + locMap["ky_KG"] = "KOI8-R"; + locMap["kk"] = "KOI8-R"; + locMap["kk_KZ"] = "KOI8-R"; + + QLocale locale(qApp->Settings()->GetLocale()); + return locMap.value(locale.name().toStdString(), "ISO8859-1"); +} diff --git a/src/libs/vdxf/dxiface.h b/src/libs/vdxf/dxiface.h index 6b61f1e60..2d835e40a 100644 --- a/src/libs/vdxf/dxiface.h +++ b/src/libs/vdxf/dxiface.h @@ -17,6 +17,8 @@ #include "libdxfrw/libdxfrw.h" #include "dxfdef.h" +class QFont; + //class to store image data and path from DRW_ImageDef class dx_ifaceImg : public DRW_Image { public: @@ -70,9 +72,9 @@ public: class dx_iface : public DRW_Interface { public: - dx_iface(const std::string& file, VarMeasurement varMeasurement, VarInsunits varInsunits); + dx_iface(const std::string& file, DRW::Version v, VarMeasurement varMeasurement, VarInsunits varInsunits); virtual ~dx_iface(); - bool fileExport(DRW::Version v, bool binary); + bool fileExport(bool binary); void writeEntity(DRW_Entity* e); //reimplement virtual DRW_Interface functions @@ -90,17 +92,21 @@ public: virtual void writeDimstyles(); virtual void writeAppId(); + void AddEntity(DRW_Entity* e); + UTF8STRING AddFont(const QFont &f); + +private: + dxfRW* dxfW; //pointer to writer, needed to send data + dx_data cData; // class to store or read data + DRW::Version version; + void InitHeader(VarMeasurement varMeasurement, VarInsunits varInsunits); void InitLTypes(); void InitLayers(); void InitTextstyles(); void InitAppId(); - void AddEntity(DRW_Entity* e); - -private: - dxfRW* dxfW; //pointer to writer, needed to send data - dx_data cData; // class to store or read data + std::string LocaleToISO() const; }; #endif // DX_IFACE_H diff --git a/src/libs/vdxf/libdxfrw/libdxfrw.cpp b/src/libs/vdxf/libdxfrw/libdxfrw.cpp index 097e23bed..7ea7d87c4 100644 --- a/src/libs/vdxf/libdxfrw/libdxfrw.cpp +++ b/src/libs/vdxf/libdxfrw/libdxfrw.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include "intern/drw_textcodec.h" #include "intern/dxfreader.h" #include "intern/dxfwriter.h" @@ -1167,7 +1169,14 @@ bool dxfRW::writeText(DRW_Text *ent){ writer->writeDouble(20, ent->basePoint.y); writer->writeDouble(30, ent->basePoint.z); writer->writeDouble(40, ent->height); - writer->writeUtf8String(1, ent->text); + + QString dxfText = QString::fromStdString(ent->text); + QTextCodec *codec = QTextCodec::codecForName("ANSI_1251"); + QByteArray encodedString = codec->fromUnicode(dxfText); + + writer->writeString(1, encodedString.constData()); + //writer->writeUtf8String(1, ent->text); + writer->writeDouble(50, ent->angle); writer->writeDouble(41, ent->widthscale); writer->writeDouble(51, ent->oblique); diff --git a/src/libs/vdxf/vdxf.pri b/src/libs/vdxf/vdxf.pri index 9760286c0..9d2e80a42 100644 --- a/src/libs/vdxf/vdxf.pri +++ b/src/libs/vdxf/vdxf.pri @@ -23,7 +23,8 @@ SOURCES += \ $$PWD/libdxfrw/drw_objects.cpp \ $$PWD/libdxfrw/libdwgr.cpp \ $$PWD/libdxfrw/libdxfrw.cpp \ - $$PWD/dxiface.cpp + $$PWD/dxiface.cpp \ + $$PWD/dxfdef.cpp win32-msvc*:SOURCES += $$PWD/stable.cpp diff --git a/src/libs/vdxf/vdxfengine.cpp b/src/libs/vdxf/vdxfengine.cpp index 845eee63e..a7bc3a0c9 100644 --- a/src/libs/vdxf/vdxfengine.cpp +++ b/src/libs/vdxf/vdxfengine.cpp @@ -78,10 +78,17 @@ VDxfEngine::VDxfEngine() matrix(), input(), varMeasurement(VarMeasurement::Metric), - varInsunits(VarInsunits::Centimeters) + varInsunits(VarInsunits::Centimeters), + textBuffer(new DRW_Text()) { } +//--------------------------------------------------------------------------------------------------------------------- +VDxfEngine::~VDxfEngine() +{ + delete textBuffer; +} + //--------------------------------------------------------------------------------------------------------------------- bool VDxfEngine::begin(QPaintDevice *pdev) { @@ -92,14 +99,14 @@ bool VDxfEngine::begin(QPaintDevice *pdev) return false; } - input = QSharedPointer(new dx_iface(fileName.toStdString(), varMeasurement, varInsunits)); + input = QSharedPointer(new dx_iface(fileName.toStdString(), m_version, varMeasurement, varInsunits)); return true; } //--------------------------------------------------------------------------------------------------------------------- bool VDxfEngine::end() { - const bool res = input->fileExport(m_version, m_binary); + const bool res = input->fileExport(m_binary); return res; } @@ -324,53 +331,49 @@ void VDxfEngine::drawEllipse(const QRect & rect) //--------------------------------------------------------------------------------------------------------------------- void VDxfEngine::drawTextItem(const QPointF & p, const QTextItem & textItem) { - const QPointF startPoint = matrix.map(p); - const double rotationAngle = atan(matrix.m12()/matrix.m11()); + if (textBuffer->text.size() == 0) + { + const QPointF startPoint = matrix.map(p); + const double rotationAngle = qRadiansToDegrees(qAtan2(matrix.m12(), matrix.m11())); - const QFont f = textItem.font(); - const int textSize = f.pixelSize() == -1 ? f.pointSize() : f.pixelSize(); + const QFont f = textItem.font(); + const UTF8STRING fontStyle = input->AddFont(f); - if (m_version > DRW::AC1009) - { // Use MTEXT - DRW_MText *text = new DRW_MText(); - text->basePoint = DRW_Coord(FromPixel(startPoint.x(), varInsunits), + textBuffer->basePoint = DRW_Coord(FromPixel(startPoint.x(), varInsunits), FromPixel(getSize().height() - startPoint.y(), varInsunits), 0); - text->secPoint = DRW_Coord(FromPixel(startPoint.x(), varInsunits), + textBuffer->secPoint = DRW_Coord(FromPixel(startPoint.x(), varInsunits), FromPixel(getSize().height() - startPoint.y(), varInsunits), 0); - text->height = textSize * matrix.m11(); - text->text = textItem.text().toStdString(); - text->style = f.family().toStdString(); - text->angle = -rotationAngle; + textBuffer->height = FromPixel(QFontMetrics(f).height(), varInsunits); - text->layer = "0"; - text->color = getPenColor(); - text->lWeight = DRW_LW_Conv::widthByLayer; - text->lineType = getPenStyle(); + textBuffer->style = fontStyle; + textBuffer->angle = -rotationAngle; - input->AddEntity(text); + textBuffer->layer = "0"; + textBuffer->color = getPenColor(); + textBuffer->lWeight = DRW_LW_Conv::widthByLayer; + textBuffer->lineType = getPenStyle(); } - else - { // Use TEXT - DRW_Text *text = new DRW_Text(); - text->basePoint = DRW_Coord(FromPixel(startPoint.x(), varInsunits), - FromPixel(getSize().height() - startPoint.y(), varInsunits), 0); - text->secPoint = DRW_Coord(FromPixel(startPoint.x(), varInsunits), - FromPixel(getSize().height() - startPoint.y(), varInsunits), 0); - text->height = textSize * matrix.m11(); - text->text = textItem.text().toStdString(); - text->style = f.family().toStdString(); - text->angle = -rotationAngle; - text->layer = "0"; - text->color = getPenColor(); - text->lWeight = DRW_LW_Conv::widthByLayer; - text->lineType = getPenStyle(); + /* Because QPaintEngine::drawTextItem doesn't pass whole string per time we mark end of each string by adding + * special placholder. */ + QString t = textItem.text(); + const bool foundEndOfString = t.contains(endStringPlaceholder); - input->AddEntity(text); + if (foundEndOfString) + { + t.replace(endStringPlaceholder, ""); + } + + textBuffer->text += t.toStdString(); + + if (foundEndOfString) + { + input->AddEntity(textBuffer); + textBuffer = new DRW_Text(); } } - //--------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- QPaintEngine::Type VDxfEngine::type() const { return QPaintEngine::User; diff --git a/src/libs/vdxf/vdxfengine.h b/src/libs/vdxf/vdxfengine.h index 240f7502b..9ae74a8d5 100644 --- a/src/libs/vdxf/vdxfengine.h +++ b/src/libs/vdxf/vdxfengine.h @@ -45,12 +45,13 @@ class QTextStream; class dx_iface; +class DRW_Text; class VDxfEngine : public QPaintEngine { public: VDxfEngine(); - virtual ~VDxfEngine() = default; + virtual ~VDxfEngine(); virtual bool begin(QPaintDevice *pdev) Q_DECL_OVERRIDE; virtual bool end() Q_DECL_OVERRIDE; @@ -98,6 +99,7 @@ private: QSharedPointer input; VarMeasurement varMeasurement; VarInsunits varInsunits; + DRW_Text *textBuffer; double FromPixel(double pix, const VarInsunits &unit) const Q_REQUIRED_RESULT; };