Warning, file /office/calligra/libs/main/KoFilterGraph.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the Calligra libraries
0002    Copyright (C) 2001 Werner Trobin <trobin@kde.org>
0003 
0004 This library is free software; you can redistribute it and/or
0005 modify it under the terms of the GNU Library General Public
0006 License as published by the Free Software Foundation; either
0007 version 2 of the License, or (at your option) any later version.
0008 
0009 This library is distributed in the hope that it will be useful,
0010 but WITHOUT ANY WARRANTY; without even the implied warranty of
0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012 Library General Public License for more details.
0013 
0014 You should have received a copy of the GNU Library General Public License
0015 along with this library; see the file COPYING.LIB.  If not, write to
0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017 Boston, MA 02110-1301, USA.
0018 */
0019 #include "KoFilterGraph.h"
0020 
0021 #include "KoFilterManager.h"  // KoFilterManager::filterAvailable, private API
0022 #include "KoDocumentEntry.h"
0023 #include "KoFilterEntry.h"
0024 #include "KoDocument.h"
0025 #include <KoConfig.h> // CALLIGRA_OLD_PLUGIN_METADATA
0026 
0027 #include "PriorityQueue_p.h"
0028 #include "KoFilterEdge.h"
0029 #include "KoFilterChainLink.h"
0030 #include "KoFilterVertex.h"
0031 
0032 #include <QPluginLoader>
0033 #include <QMetaMethod>
0034 #include <MainDebug.h>
0035 
0036 #include <limits.h> // UINT_MAX
0037 
0038 
0039 namespace CalligraFilter {
0040 
0041 Graph::Graph(const QByteArray& from)
0042         : m_from(from)
0043         , m_graphValid(false)
0044         , d(0)
0045 {
0046     buildGraph();
0047     shortestPaths();  // Will return after a single lookup if "from" is invalid (->no check here)
0048 }
0049 
0050 Graph::~Graph()
0051 {
0052     foreach(Vertex* vertex, m_vertices) {
0053         delete vertex;
0054     }
0055     m_vertices.clear();
0056 }
0057 
0058 void Graph::setSourceMimeType(const QByteArray& from)
0059 {
0060     if (from == m_from)
0061         return;
0062     m_from = from;
0063     m_graphValid = false;
0064 
0065     // Initialize with "infinity" ...
0066     foreach(Vertex* vertex, m_vertices) {
0067         vertex->reset();
0068     }
0069     // ...and re-run the shortest path search for the new source mime
0070     shortestPaths();
0071 }
0072 
0073 KoFilterChain::Ptr Graph::chain(const KoFilterManager* manager, QByteArray& to) const
0074 {
0075     if (!isValid() || !manager)
0076         return KoFilterChain::Ptr();
0077 
0078     if (to.isEmpty()) {    // if the destination is empty we search the closest Calligra part
0079         to = findCalligraPart();
0080         if (to.isEmpty())    // still empty? strange stuff...
0081             return KoFilterChain::Ptr();
0082     }
0083 
0084     const Vertex* vertex = m_vertices.value(to);
0085     if (!vertex || vertex->key() == UINT_MAX)
0086         return KoFilterChain::Ptr();
0087 
0088     KoFilterChain::Ptr ret(new KoFilterChain(manager));
0089 
0090     // Fill the filter chain with all filters on the path
0091     const Vertex* tmp = vertex->predecessor();
0092     while (tmp) {
0093         const Edge* const edge = tmp->findEdge(vertex);
0094         Q_ASSERT(edge);
0095         ret->prependChainLink(edge->filterEntry(), tmp->mimeType(), vertex->mimeType());
0096         vertex = tmp;
0097         tmp = tmp->predecessor();
0098     }
0099     return ret;
0100 }
0101 
0102 void Graph::dump() const
0103 {
0104 #ifndef NDEBUG
0105     debugFilter << "+++++++++ Graph::dump +++++++++";
0106     debugFilter << "From:" << m_from;
0107     foreach(Vertex *vertex, m_vertices) {
0108         vertex->dump("   ");
0109     }
0110     debugFilter << "+++++++++ Graph::dump (done) +++++++++";
0111 #endif
0112 }
0113 
0114 // Query the trader and create the vertices and edges representing
0115 // available mime types and filters.
0116 void Graph::buildGraph()
0117 {
0118     // Make sure that all available parts are added to the graph
0119     const QList<KoDocumentEntry> parts(KoDocumentEntry::query());
0120 
0121     foreach(const KoDocumentEntry& part, parts) {
0122 
0123         QJsonObject metaData = part.metaData();
0124 #ifdef CALLIGRA_OLD_PLUGIN_METADATA
0125         QStringList nativeMimeTypes = metaData.value("X-KDE-ExtraNativeMimeTypes").toString().split(',');
0126 #else
0127         QStringList nativeMimeTypes = metaData.value("X-KDE-ExtraNativeMimeTypes").toVariant().toStringList();
0128 #endif
0129         nativeMimeTypes += metaData.value("X-KDE-NativeMimeType").toString();
0130 
0131         foreach(const QString& nativeMimeType, nativeMimeTypes) {
0132             const QByteArray key = nativeMimeType.toLatin1();
0133             if (!m_vertices.contains(key))
0134                 m_vertices[key] = new Vertex(key);
0135         }
0136     }
0137 
0138     // no constraint here - we want *all* :)
0139     const QList<KoFilterEntry::Ptr> filters(KoFilterEntry::query());
0140 
0141     foreach(KoFilterEntry::Ptr filter, filters) {
0142 
0143         // First add the "starting points" to the dict
0144         foreach (const QString& import, filter->import) {
0145             const QByteArray key = import.toLatin1();    // latin1 is okay here (werner)
0146             // already there?
0147             if (!m_vertices.contains(key))
0148                 m_vertices.insert(key, new Vertex(key));
0149         }
0150 
0151         // Are we allowed to use this filter at all?
0152         if (KoFilterManager::filterAvailable(filter)) {
0153 
0154             foreach(const QString& exportIt, filter->export_) {
0155 
0156                 // First make sure the export vertex is in place
0157                 const QByteArray key = exportIt.toLatin1();    // latin1 is okay here
0158                 Vertex* exp = m_vertices.value(key);
0159                 if (!exp) {
0160                     exp = new Vertex(key);
0161                     m_vertices.insert(key, exp);
0162                 }
0163                 // Then create the appropriate edges
0164                 foreach(const QString& import, filter->import) {
0165                     m_vertices[import.toLatin1()]->addEdge(new Edge(exp, filter));
0166                 }
0167             }
0168         } else
0169             debugFilter << "Filter:" << filter->fileName() << " doesn't apply.";
0170     }
0171 }
0172 
0173 // As all edges (=filters) are required to have a positive weight
0174 // we can use Dijkstra's shortest path algorithm from Cormen's
0175 // "Introduction to Algorithms" (p. 527)
0176 // Note: I did some adaptions as our data structures are slightly
0177 // different from the ones used in the book. Further we simply stop
0178 // the algorithm is we don't find any node with a weight != Infinity
0179 // (==UINT_MAX), as this means that the remaining nodes in the queue
0180 // aren't connected anyway.
0181 void Graph::shortestPaths()
0182 {
0183     // Is the requested start mime type valid?
0184     Vertex* from = m_vertices.value(m_from);
0185     if (!from)
0186         return;
0187 
0188     // Inititalize start vertex
0189     from->setKey(0);
0190 
0191     // Fill the priority queue with all the vertices
0192     PriorityQueue<Vertex> queue(m_vertices);
0193 
0194     while (!queue.isEmpty()) {
0195         Vertex *min = queue.extractMinimum();
0196         // Did we already relax all connected vertices?
0197         if (min->key() == UINT_MAX)
0198             break;
0199         min->relaxVertices(queue);
0200     }
0201     m_graphValid = true;
0202 }
0203 
0204 QByteArray Graph::findCalligraPart() const
0205 {
0206     // Here we simply try to find the closest Calligra mimetype
0207     const QList<KoDocumentEntry> parts(KoDocumentEntry::query());
0208     QList<KoDocumentEntry>::ConstIterator partIt(parts.constBegin());
0209     QList<KoDocumentEntry>::ConstIterator partEnd(parts.constEnd());
0210 
0211     const Vertex *v = 0;
0212 
0213     // Be sure that v gets initialized correctly
0214     while (!v && partIt != partEnd) {
0215         QJsonObject metaData = (*partIt).metaData();
0216 #ifdef CALLIGRA_OLD_PLUGIN_METADATA
0217         QStringList nativeMimeTypes = metaData.value("X-KDE-ExtraNativeMimeTypes").toString().split(',');
0218 #else
0219         QStringList nativeMimeTypes = metaData.value("X-KDE-ExtraNativeMimeTypes").toVariant().toStringList();
0220 #endif
0221         nativeMimeTypes += metaData.value("X-KDE-NativeMimeType").toString();
0222         QStringList::ConstIterator it = nativeMimeTypes.constBegin();
0223         QStringList::ConstIterator end = nativeMimeTypes.constEnd();
0224         for (; !v && it != end; ++it)
0225             if (!(*it).isEmpty())
0226                 v = m_vertices.value((*it).toLatin1());
0227         ++partIt;
0228     }
0229     if (!v)
0230         return "";
0231 
0232     // Now we try to find the "cheapest" Calligra vertex
0233     while (partIt != partEnd) {
0234         QJsonObject metaData = (*partIt).metaData();
0235 #ifdef CALLIGRA_OLD_PLUGIN_METADATA
0236         QStringList nativeMimeTypes = metaData.value("X-KDE-ExtraNativeMimeTypes").toString().split(',');
0237 #else
0238         QStringList nativeMimeTypes = metaData.value("X-KDE-ExtraNativeMimeTypes").toVariant().toStringList();
0239 #endif
0240         nativeMimeTypes += metaData.value("X-KDE-NativeMimeType").toString();
0241         QStringList::ConstIterator it = nativeMimeTypes.constBegin();
0242         QStringList::ConstIterator end = nativeMimeTypes.constEnd();
0243         for (; !v && it != end; ++it) {
0244             QString key = *it;
0245             if (!key.isEmpty()) {
0246                 Vertex* tmp = m_vertices.value(key.toLatin1());
0247                 if (!v || (tmp && tmp->key() < v->key()))
0248                     v = tmp;
0249             }
0250         }
0251         ++partIt;
0252     }
0253 
0254     // It seems it already is a Calligra part
0255     if (v->key() == 0)
0256         return "";
0257 
0258     return v->mimeType();
0259 }
0260 }