Subversion Repositories Scribus

Rev

Rev 23294 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/

/***************************************************************************
 *   Copyright (C) 2004 by Riku Leino                                      *
 *   tsoots@gmail.com                                                      *
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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.             *
 ***************************************************************************/


#include "gtgettext.h"
#include "pluginmanager.h"
#include "scpaths.h"
#include "pageitem.h"
#include "scribusdoc.h"
#include "selection.h"
#include "ui/gtdialogs.h"
#include "gtwriter.h"
#include <QPixmap>

// Constructor
gtGetText::gtGetText(ScribusDoc* doc)
{
        m_dias = nullptr;
        // Attach to the active document
        m_Doc = doc;
        // Load the plugins array.
        loadImporterPlugins();
} // gtGetText::gtGetText(ScribusDoc* doc)

// Look at the results of the file selection dialog and figure out if you need to use an importer.
// Prompt the user if the importer to use isn't obvious.
void gtGetText::launchImporter(int importer, const QString& filename, bool textOnly,
                                                                const QString& encoding, bool append, bool prefix, PageItem* target)
{
        // Struct for the plugin info, we'll load this up from the array.
        struct ImporterData ida;
        // Do we need to call an importer? Unsure what happens if this ever becomes false.
        bool callImporter = true;
        // Check and see if the file selection dialog returned the index position of the
        // importer to be used. If it isn't, try to figure out what it is. If we can't,
        // prompt the user.
        if (importer == -1)
        {
                // Attempt to determine the importer based on the file's extension.
                // Create a Qstring with what could be an extension.
                QString fend = filename.right(filename.length() - filename.lastIndexOf(".") - 1);
                QString fendL(fend.toLower());
                // Look for that extension in the importer QMap.
                if (m_importerMap.find(fend) != m_importerMap.end())
                        // If the map is found, assign ida to the corresponding struct in the map.
                        ida = *m_importerMap[fend];
                // Otherwise, test for the lowercase version
                else if (m_importerMap.find(fendL) != m_importerMap.end())
                        // If the map is found, assign ida to the corresponding struct in the map.
                        ida = *m_importerMap[fendL];
                // Otherwise, try and ask the user.
                else
                {
                        // Create a new dialog
                        m_dias = new gtDialogs();
                        // Pop up the dialog asking the user to select the type from our list (ilist) of
                        // importable file types. If one is not selected, set callImporter to false.
                        callImporter = m_dias->runImporterDialog(filename, m_ilist);
                        // If we're gonna call an importer, we need to copy it's struct to ida.
                        if (callImporter)
                                ida = m_importers[m_dias->getImporter()];
                        // Destroy the diag
                        delete m_dias;
                } // else - if (importerMap.find(fend) != importerMap.end())
        }
        else // If we know which importer to use
        {
                // Copy the importer's struct to ida.
                ida = m_importers[importer];
        }       // else - if (importer == -1)
       
        // Create a target text frame for the imported text and assign it to the parameter "target"
        PageItem* targetFrame=target;
       
        // If the targetframe is 0 ( no frame selected/created? ) then reassign it to the
        // (questionable interpretation here) first frame in the documentation.
        if (targetFrame==nullptr)
                targetFrame=m_Doc->m_Selection->itemAt(0);

        // If the targetframe is not zero, and we do need to call the importer,
        // Run the importer via "CallDLL" and pass it what it needs to know.
        if (targetFrame!=nullptr && callImporter)
                CallDLL(ida, filename, encoding, textOnly, append, prefix, targetFrame);
}  //void gtGetText::launchImporter(int importer, const QString& filename, bool textOnly,
   //                                           const QString& encoding, bool append, PageItem* target)

// Find the available plugins based on the environment, validate they load, and
// create quick lookup mappings.
void gtGetText::loadImporterPlugins()
{
        // Get the path to the plugins
        QString gtdir = ScPaths::instance().pluginDir();
        // Append the gettext path to the plugin
        gtdir += "gettext";
        // Set the search parameteer for the platform specific extension for the plugins ( DLL, so, etc. )
        QString libPattern = QString("*.%1*").arg(PluginManager::platformDllExtension());
        // Search for matches.
        QDir d(gtdir, libPattern, QDir::Name, (QDir::Filter) PluginManager::platformDllSearchFlags());

        // Initialize a structure for the importers found
        struct ImporterData ida;
        ida.fileFormatName = "";

        // Check and see if the directory existed and if the count of files matching is greater than 0.
        if ((d.exists()) && (d.count() != 0))
        {
                // loop through the entries.
                for (uint dc = 0; dc < d.count(); ++dc)
                {
                        // Verify the Plugin will load. If it does, collect the info on the plugin ( Name, extension, format, etc )
                        if (DLLName(d[dc], &ida.fileFormatName, &ida.fileEndings))
                        {
                                // no plugin's "format name" marks "don't load plug"
                                if (ida.fileFormatName.isNull())
                                        continue;
                                // Store the path to the plugin.
                                ida.soFilePath = d[dc];
                                // If the plugin path does not begin with /, prepend a /.
                                if (ida.soFilePath.left(1) != "/")
                                        ida.soFilePath = "/" + ida.soFilePath;
                                // Add the plugin data to the end of the importer's vector.
                                m_importers.push_back(ida);
                        }       // if (DLLName(d[dc], &ida.fileFormatName, &ida.fileEndings))
                }  // for (uint dc = 0; dc < d.count(); ++dc)
        }  // if ((d.exists()) && (d.count() != 0))
        // Create the Importer Extension to Plugin data qmap.
        createMap();
}  // void gtGetText::loadImporterPlugins()


QStringList gtGetText::getSupportedTypes()
{
        QStringList result;
        for (size_t i = 0; i < m_importers.size(); ++i)
        {
                const ImporterData& importerData = m_importers[i];
                if (importerData.fileEndings.count() <= 0)
                        continue;
                for (int j = 0; j < importerData.fileEndings.count(); ++j)
                        result.append(importerData.fileEndings[j].toLower());
        }
        return result;
}

// Creates the dialog for the user to import a file based on the supported file formats.
ImportSetup gtGetText::run()
{
        // Initialize a filters list.
        QString filters;

        // Create a string for the "All supported files filter". Start with the label then loop through
        // the importers vector and add all of the file extensions supported.
        QString allSupported = QObject::tr("All Supported Formats") + " (";
        // Loop through the importers vector.
        for (size_t i = 0; i < m_importers.size(); ++i)
        {
                const ImporterData& importerData = m_importers[i];
                // If there are any file extnsions declared by the importer
                if (importerData.fileEndings.count() <= 0)
                        continue;
                // Add the importer name to the filters list
                filters += importerData.fileFormatName + " (";
                // Loop though the extensions supported by the importer
                for (int j = 0; j < importerData.fileEndings.count(); ++j)
                {
                        // Add the extension to both the filter and allSupported strings
                        filters += "*." + importerData.fileEndings[j] + " ";
                        allSupported += "*." + importerData.fileEndings[j] + " ";
                }
                // Trim the Qstring
                filters = filters.trimmed();
                // Append "entry of entry" information to the end of the filter.
                filters += ");;";
        }

        // Trim the allSupported QString and append "end of entry" data to the end of it.
        allSupported = allSupported.trimmed();
        allSupported += ");;";

        // Prepend allSupported to the filters Qstring.
        filters = allSupported + filters;
        // Add an "all files" entry to the end of the filters QString
        filters += QObject::tr("All Files (*)");
        // Populate ilist with the file importer names.
        for (size_t i = 0;  i < m_importers.size(); ++i)
                m_ilist.append(m_importers[i].fileFormatName);

        // Create a new dialog.
        m_dias = new gtDialogs();
        // Create a new ImportSetup struct
        ImportSetup impsetup;
        // INitialize runDialog to false
        impsetup.runDialog=false;
        // If we get a true back from the File selection Dialog ( which we send our filters and extensions lists )
        if (m_dias->runFileDialog(filters, m_ilist))
        {
                // Set the runDialog to true
                impsetup.runDialog = true;
                // Copy the other values for the struct from the dialog results
                impsetup.encoding = m_dias->getEncoding();
                impsetup.filename = m_dias->getFileName();
                impsetup.importer = m_dias->getImporter();
                impsetup.textOnly = m_dias->importTextOnly();
                impsetup.prefixNames = m_dias->prefixStyles();
        }
        // Destroy the dialog.
        delete m_dias;
        // Return the ImportSetup struct.
        return impsetup;
}  // ImportSetup gtGetText::run()

// Loads, validates, and executes the Importer code.
void gtGetText::CallDLL(const ImporterData& idata, const QString& filePath,
                                                const QString& encoding, bool textOnly, bool append, bool prefix, PageItem* importItem)
{
        // Pointer for the loaded plugin.
        void* gtplugin;
        // Type definition for GetText pointer in the function in question.
        typedef void (*gt2ptr)(const QString& filename, const QString& encoding, bool textOnly, bool prefix, bool append, PageItem *textframe);
        // Type definition for GetText pointer in the function in question.
        typedef void (*sdem)(const QString& filename, const QString& encoding, bool textOnly, gtWriter *writer);
        // The point to the above.
        gt2ptr fp_GetText2;
        sdem fp_GetText;
        // Initialize Path to the "DLL"
        QString pluginFilePath = QString("%1/gettext/%2").arg(ScPaths::instance().pluginDir(), idata.soFilePath);
        // Attempt to load the plugin, store the pointer in gtplugin
        gtplugin = PluginManager::loadDLL(pluginFilePath);
        // If gtplugin is nullptr we failed to load the plugin. Report an error to the user and exit the method.
        if (!gtplugin)
        {
                qWarning("Failed to load plugin %s", pluginFilePath.toLatin1().constData());
                return;
        } // if (!gtplugin)

        fp_GetText2 = (gt2ptr) PluginManager::resolveSym(gtplugin,"GetText2");
        if (fp_GetText2)
        {
                if (!append)
                        importItem->itemText.clear();
                // Execute the importer's "GetText2" method.
                (*fp_GetText2)(filePath, encoding, textOnly, prefix, append, importItem);
        }  // if (!fp_GetText2)        
        else
        {
                // Attempt to map the old GetText method to to the pointer via the PluginManager. Store the result in fp_GetText.
                fp_GetText = (sdem) PluginManager::resolveSym(gtplugin,"GetText");
                // If fp_GetText is nullptr, we could not find the symbol,report the error, unload the "DLL" and exit the method.
                if (fp_GetText)
                {
                        // Create a new writer object in "append"'s mode (true or false ) attached to the importItem
                        gtWriter *w = new gtWriter(append, importItem);
                        // Execute the importer's "GetText" method.
                        (*fp_GetText)(filePath, encoding, textOnly, w);
                        // Destroy the writer
                        delete w;
                }  // if (!fp_GetText)
                else
                {
                        qWarning("Failed to get GetText() from %s",pluginFilePath.toLatin1().constData());
                }
        }
        // GetText is not quite up to date vs styles, clean char formatting already specified at paragraph level
        importItem->itemText.fixLegacyFormatting();
        // Unload the plugin.
        PluginManager::unloadDLL(gtplugin);
}  // void gtGetText::CallDLL(const ImporterData& idata, const QString& filePath,
   //                     const QString& encoding, bool textOnly, bool append, PageItem* importItem)

// Loads the "DLL", validates the importer is good, populates the passed parameters with
// the plugin information.
bool gtGetText::DLLName(const QString& name, QString *ffName, QStringList *fEndings)
{
        // Pointer to the plugin, once loaded
        void* gtplugin;
        // typedef of Qstring to map the importer name (FileFormatName) method results to.
        typedef QString (*sdem0)();
        // typedef of QStringList to map the file extensions supported method results to.
        typedef QStringList (*sdem1)();
        // The actual importer name object
        sdem0 fp_FileFormatName;
        // The actual extensions supported object
        sdem1 fp_FileExtensions;
        // Initialise the plugin file path ( with filename )
        QString pluginFilePath = QString("%1/gettext/%2").arg(ScPaths::instance().pluginDir(), name);
        // Attempt to load the plugin.
        gtplugin = PluginManager::loadDLL(pluginFilePath);
        // if gtplugin is nullptr we were unable to load the plugin. Return an error and exit the method.
        if (!gtplugin)
        {
                qWarning("Failed to load plugin %s", pluginFilePath.toLatin1().constData());
                return false;
        }
        // Attempt to resolve the plugin symbol to the importer name (FileFormatName)
        fp_FileFormatName = (sdem0) PluginManager::resolveSym( gtplugin, "FileFormatName");
        // if fp_FileFormatName is nullptr, we could not find the FileFormatName symbol. The plugin is incomplete.
        // Report an error, unload the plugin, and exit the method.
        if (!fp_FileFormatName)
        {
                qWarning("Failed to get FileFormatName() from %s", pluginFilePath.toLatin1().constData());
                PluginManager::unloadDLL(gtplugin);
                return false;
        }
        // Attempt to resolve the plugin symbol to the list of supported file extensions.
        fp_FileExtensions = (sdem1) PluginManager::resolveSym( gtplugin, "FileExtensions");
        // if fp_FileExtensions is nullptr, we could not find the FileExtensions symbol. The plugin is incomplete.
        // Report an error, unload the plugin, and exit the method.
        if (!fp_FileExtensions)
        {
                qWarning("Failed to get FileExtensions() from %s", pluginFilePath.toLatin1().constData());
                PluginManager::unloadDLL(gtplugin);
                return false;
        }
        // Set the format name based on the resolved method.
        *ffName = (*fp_FileFormatName)();
        // Set the extensions list based on the resolved method.
        *fEndings = (*fp_FileExtensions)();
        // Unload the plugin
        PluginManager::unloadDLL(gtplugin);
        // Successfully return!
        return true;
}  // bool gtGetText::DLLName(QString name, QString *ffName, QStringList *fEndings)

// Create the importer Qmap.
void gtGetText::createMap()
{
        // Loop through the importers Vector
        for (uint i = 0; i < m_importers.size(); ++i)
        {
                // Loop through each file extension the importer uses/importers and create an individual
                // Qmap entry for it.
                for (int j = 0; j < m_importers[i].fileEndings.count(); ++j)
                                m_importerMap.insert(m_importers[i].fileEndings[j], &m_importers[i]);
        }  // for (uint i = 0; i < importers.size(); ++i)
}  // void gtGetText::createMap()

// Destructor
gtGetText::~gtGetText()
{
        // Nothing needs to happen here.
}