/**************************************************************************** ** ** This file is part of the LibreCAD project, a 2D CAD program ** ** Copyright (C) 2021 A. Stebich (librecad@mail.lordofbikes.de) ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl) ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved. ** ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file gpl-2.0.txt included in the ** packaging of this file. ** ** This program 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 this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ** ** This copyright notice MUST APPEAR in all copies of the script! ** **********************************************************************/ #include #include #include #ifdef DWGSUPPORT #include #include #endif #include "rs_fileio.h" #include "rs_filtercxf.h" #include "rs_filterdxf1.h" #include "rs_filterjww.h" #include "rs_filterlff.h" #include "rs_filterdxfrw.h" #include "rs_debug.h" /** * Calls the import method of the filter responsible for the format * of the given file. * * @param graphic The container to which we will add * entities. Usually that's an RS_Graphic entity but * it can also be a polyline, text, ... * @param file Path and name of the file to import. */ bool RS_FileIO::fileImport(RS_Graphic& graphic, const QString& file, RS2::FormatType type) { RS_DEBUG->print("Trying to import file '%s'...", file.toLatin1().data()); RS2::FormatType t; if (type == RS2::FormatUnknown) { t = detectFormat(file); } else { t = type; } if (RS2::FormatUnknown != t) { std::unique_ptr&& filter(getImportFilter(file, t)); if (filter){ #ifdef DWGSUPPORT bool isDwg {file.endsWith( ".dwg", Qt::CaseInsensitive)}; if (isDwg) { QApplication::restoreOverrideCursor(); // disable WaitCursor for massagebox // use QStringList to avoid "\n" in translation strings QStringList info { QObject::tr("DWG support is not complete!"), "", QObject::tr("If this file fails to open try an older DWG format"), QObject::tr("or try to find a converter to make it a DXF file.") }; QMessageBox::information( qApp->activeWindow(), QObject::tr("Information"), info.join( "\n"), QMessageBox::Ok, QMessageBox::NoButton); QApplication::setOverrideCursor( QCursor(Qt::WaitCursor)); } #endif bool bImported {filter->fileImport(graphic, file, t)}; if (!bImported) { QApplication::restoreOverrideCursor(); // disable WaitCursor for massagebox QString strTitle {QObject::tr("Error", "fileImport")}; QString strError {QObject::tr("Import error:", "fileImport")}; QString strLastError( " %1"); #ifdef DWGSUPPORT if (isDwg) { if (graphic.isEmpty()) { QMessageBox::critical( qApp->activeWindow(), strTitle, QStringList( {strError, strLastError}).join( "\n").arg( filter->lastError()), QMessageBox::Ok, QMessageBox::NoButton); } else { QStringList message { strError, strLastError, "", QObject::tr("Anyhow, there are some entities identified.", "dwgImport"), QObject::tr("If you open the file now, the drawing may be not complete or unusable.", "dwgImport"), "", QObject::tr("Ignore error and open the file?", "dwgImport"), }; QMessageBox::StandardButton answer = QMessageBox::warning( qApp->activeWindow(), QObject::tr("Warning"), message.join( "\n").arg( filter->lastError()), QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton); if (QMessageBox::Yes == answer) { return true; // open the file anyhow } } } else #endif { QMessageBox::critical( qApp->activeWindow(), strTitle, QStringList( {strError, strLastError}).join( "\n").arg( filter->lastError()), QMessageBox::Ok, QMessageBox::NoButton); } QApplication::setOverrideCursor( QCursor(Qt::WaitCursor)); } return bImported; } RS_DEBUG->print(RS_Debug::D_WARNING, "RS_FileIO::fileImport: failed to import file: %s", file.toLatin1().data()); } else { RS_DEBUG->print(RS_Debug::D_WARNING, "RS_FileIO::fileImport: failed to detect file format: %s", file.toLatin1().data()); } return false; } /** \brief extension2Type convert extension to file format type * \param file type * \param verifyRead read the file to verify dxf/dxfrw type, default to false * \return file format type */ RS2::FormatType RS_FileIO::detectFormat(QString const& file, bool forRead) { // look up table std::map list{ {"dxf", RS2::FormatDXFRW}, {"cxf", RS2::FormatCXF}, {"lff", RS2::FormatLFF} }; // only read support for dwg if(forRead) list["dwg"]=RS2::FormatDWG; QString const extension = QFileInfo(file).suffix().toLower(); RS2::FormatType type=(list.find(extension)!= list.end()) ? list[extension]:RS2::FormatUnknown; //only read dxf to verify if (forRead && type==RS2::FormatDXFRW) { type = RS2::FormatDXFRW; QFile f(file); if (!f.open(QIODevice::ReadOnly)) { // Error opening file: RS_DEBUG->print(RS_Debug::D_WARNING, "%s:" "Cannot open file: %s", __func__, file.toLatin1().data()); type = RS2::FormatUnknown; } else { RS_DEBUG->print("%s:" "Successfully opened DXF file: %s", __func__, file.toLatin1().data()); QTextStream ts(&f); QString line; int c=0; while (!ts.atEnd() && ++c<100) { line = ts.readLine(); if (line=="$ACADVER" || line=="ENTITIES") { type = RS2::FormatDXFRW; break; } // very simple reduced DXF: // if (line=="ENTITIES" && c<10) { // type = RS2::FormatDXFRW; // } } f.close(); } } return type; } /** * Calls the export method of the object responsible for the format * of the given file. * * @param file Path and name of the file to import. */ bool RS_FileIO::fileExport(RS_Graphic& graphic, const QString& file, RS2::FormatType type) { RS_DEBUG->print("RS_FileIO::fileExport"); //RS_DEBUG->print("Trying to export file '%s'...", file.latin1()); if (type==RS2::FormatUnknown) { type=detectFormat(file, false); } std::unique_ptr&& filter(getExportFilter(file, type)); if (filter){ return filter->fileExport(graphic, file, type); } RS_DEBUG->print("RS_FileIO::fileExport: no filter found"); return false; } RS_FileIO* RS_FileIO::instance() { static RS_FileIO* uniqueInstance=nullptr; if (!uniqueInstance) { uniqueInstance = new RS_FileIO(); } return uniqueInstance; } /** * @return Filter which can import the given file type. */ std::unique_ptr RS_FileIO::getImportFilter(const QString &fileName, RS2::FormatType t) const{ for(auto f: getFilters()){ std::unique_ptr filter(f()); if(filter && filter->canImport(fileName, t)){ return filter; } } return nullptr; } /** * @return Filter which can export the given file type. */ std::unique_ptr RS_FileIO::getExportFilter(const QString &fileName, RS2::FormatType t) const{ for(auto f: getFilters()){ std::unique_ptr filter(f()); if(filter && filter->canExport(fileName, t)){ return filter; } } return nullptr; } std::vector> RS_FileIO::getFilters(){ return { RS_FilterLFF::createFilter ,RS_FilterDXFRW::createFilter ,RS_FilterCXF::createFilter ,RS_FilterJWW::createFilter ,RS_FilterDXF1::createFilter }; }