You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/lib/kofficecore/KoFilterChain.h

411 lines
14 KiB

/* This file is part of the KOffice libraries
Copyright (C) 2001 Werner Trobin <trobin@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __koffice_filter_chain_h__
#define __koffice_filter_chain_h__
#include <tqcstring.h>
#include <tqasciidict.h>
#include <tqptrlist.h>
#include <tqstringlist.h>
#include <KoFilter.h>
#include <KoQueryTrader.h>
#include <KoStoreDevice.h>
#include <koffice_export.h>
class KTempFile;
class KoFilterManager;
class KoDocument;
class TQStrList;
namespace KOffice {
class Graph;
}
/**
* @brief This class represents a chain of plain @ref KoFilter instances.
*
* Instances of this class are shared, so please just hold
* KoFilterChain::Ptr pointers to it.
*
* @author Werner Trobin <trobin@kde.org>
* @todo the class has no constructor and therefore cannot initialize its private class
*/
class KOFFICECORE_EXPORT KoFilterChain : public TDEShared
{
// Only KOffice::Graph is allowed to construct instances and
// add chain links.
friend class KOffice::Graph;
friend class KoFilterManager;
public:
typedef TDESharedPtr<KoFilterChain> Ptr;
virtual ~KoFilterChain();
/**
* The filter manager returned may be 0!
*/
const KoFilterManager* manager() const { return m_manager; }
/**
* Starts the filtering process.
* @return The return status of the conversion. KoFilter::OK
* if everything is alright.
*/
KoFilter::ConversionStatus invokeChain();
/**
* Tells the @ref KoFilterManager the output file of the
* filter chain in case of an import operation. If it's
* TQString() we directly manipulated the document.
*/
TQString chainOutput() const;
/**
* Get the current file to read from. This part of the API
* is for the filters in our chain.
*/
TQString inputFile();
/**
* Get the current file to write to. This part of the API
* is for the filters in our chain.
*/
TQString outputFile();
/**
* Get a file from a storage. May return 0!
* This part of the API is for the filters in our chain.
* If you call it multiple times with the same stream name
* the stream will be closed and re-opened.
* Note: @em Don't delete that @ref KoStoreDevice we return.
* @param name The name of the stream inside the storage
* @param mode Whether we want to read or write from/to the stream
* @return The storage device to access the stream. May be 0!
*/
KoStoreDevice* storageFile( const TQString& name = "root", KoStore::Mode mode = KoStore::Read );
/**
* This method allows your filter to work directly on the
* @ref KoDocument of the application.
* This part of the API is for the filters in our chain.
* @return The document containing the data. May return 0 on error.
*/
KoDocument* inputDocument();
/**
* This method allows your filter to work directly on the
* @ref KoDocument of the application.
* This part of the API is for the filters in our chain.
* @return The document you have to write to. May return 0 on error.
*/
KoDocument* outputDocument();
// debugging
void dump() const;
private:
// ### API for KOffice::Graph:
// Construct a filter chain belonging to some KoFilterManager.
// The parent filter manager may be 0.
KoFilterChain( const KoFilterManager* manager );
void appendChainLink( KoFilterEntry::Ptr filterEntry, const TQCString& from, const TQCString& to );
void prependChainLink( KoFilterEntry::Ptr filterEntry, const TQCString& from, const TQCString& to );
// ### API for KoEmbeddingFilter
// This is needed as the embedding filter might have to influence
// the way we change directories (e.g. in the olefilter case)
// The ugly friend methods are needed, but I'd welcome and suggestions for
// better design :}
friend void KoEmbeddingFilter::filterChainEnterDirectory( const TQString& directory ) const;
void enterDirectory( const TQString& directory );
friend void KoEmbeddingFilter::filterChainLeaveDirectory() const;
void leaveDirectory();
// These methods are friends of KoFilterManager and provide access
// to a private part of its API. As I don't want to include
// koFilterManager.h in this header the direction is "int" here.
TQString filterManagerImportFile() const;
TQString filterManagerExportFile() const;
KoDocument* filterManagerKoDocument() const;
int filterManagerDirection() const;
KoFilterChain* const filterManagerParentChain() const;
// Helper methods which keep track of all the temp files, documents,
// storages,... and properly delete them as soon as they are not
// needed anymore.
void manageIO();
void finalizeIO();
bool createTempFile( KTempFile** tempFile, bool autoDelete = true );
void inputFileHelper( KoDocument* document, const TQString& alternativeFile );
void outputFileHelper( bool autoDelete );
KoStoreDevice* storageNewStreamHelper( KoStore** storage, KoStoreDevice** device, const TQString& name );
KoStoreDevice* storageHelper( const TQString& file, const TQString& streamName,
KoStore::Mode mode, KoStore** storage, KoStoreDevice** device );
void storageInit( const TQString& file, KoStore::Mode mode, KoStore** storage );
KoStoreDevice* storageInitEmbedding( const TQString& name );
KoStoreDevice* storageCreateFirstStream( const TQString& streamName, KoStore** storage, KoStoreDevice** device );
KoStoreDevice* storageCleanupHelper( KoStore** storage );
KoDocument* createDocument( const TQString& file );
KoDocument* createDocument( const TQCString& mimeType );
/**
* A small private helper class with represents one single filter
* (one link of the chain)
* @internal
*/
class ChainLink
{
public:
ChainLink( KoFilterChain* chain, KoFilterEntry::Ptr filterEntry,
const TQCString& from, const TQCString& to );
KoFilter::ConversionStatus invokeFilter( const ChainLink* const parentChainLink );
TQCString from() const { return m_from; }
TQCString to() const { return m_to; }
// debugging
void dump() const;
// This hack is only needed due to crappy Microsoft design and
// circular dependencies in their embedded files :}
int lruPartIndex() const;
private:
ChainLink( const ChainLink& rhs );
ChainLink& operator=( const ChainLink& rhs );
void setupCommunication( const KoFilter* const parentFilter ) const;
void setupConnections( const KoFilter* sender, const TQStrList& sigs,
const KoFilter* receiver, const TQStrList& sl0ts ) const;
KoFilterChain* m_chain;
KoFilterEntry::Ptr m_filterEntry;
TQCString m_from, m_to;
// This hack is only needed due to crappy Microsoft design and
// circular dependencies in their embedded files :}
KoFilter* m_filter;
class Private;
Private* d;
};
// "A whole is that which has beginning, middle, and end" - Aristotle
// ...but we also need to signal "Done" state, Mr. Aristotle
enum Whole { Beginning = 1, Middle = 2, End = 4, Done = 8 };
// Don't copy or assign filter chains
KoFilterChain( const KoFilterChain& rhs );
KoFilterChain& operator=( const KoFilterChain& rhs );
const KoFilterManager* const m_manager;
TQPtrList<ChainLink> m_chainLinks;
// stuff needed for bookkeeping
int m_state;
TQString m_inputFile; // Did we pass around plain files?
TQString m_outputFile;
KoStore* m_inputStorage; // ...or was it a storage+device?
KoStoreDevice* m_inputStorageDevice;
KoStore* m_outputStorage;
KoStoreDevice* m_outputStorageDevice;
KoDocument* m_inputDocument; // ...or even documents?
KoDocument* m_outputDocument;
KTempFile* m_inputTempFile;
KTempFile* m_outputTempFile;
// These two flags keep track of the input/output the
// filter (=user) asked for
enum IOState { Nil, File, Storage, Document };
IOState m_inputQueried, m_outputQueried;
// This stack keeps track of directories we have to enter and
// leave due to internal embedding a la OLE filters. This serves
// as a kind of "memory" even if we didn't initialize the store yet.
// I know that it's ugly, and I'll try to clean up that hack
// sooner or later (Werner)
TQStringList m_internalEmbeddingDirectories;
class Private;
Private* d;
};
// As we use quite generic classnames...
namespace KOffice
{
class Vertex;
template<class T> class PriorityQueue;
/**
* An internal class representing a filter (=edge) in the filter graph.
* @internal
*/
class Edge
{
public:
// creates a new edge to "vertex" with the given weight.
Edge( Vertex* vertex, KoFilterEntry::Ptr filterEntry );
~Edge() {}
unsigned int weight() const { return m_filterEntry ? m_filterEntry->weight : 0; }
KoFilterEntry::Ptr filterEntry() const { return m_filterEntry; }
const Vertex* vertex() const { return m_vertex; }
// Relaxes the "connected" vertex (i.e. the weight of the
// connected vertex = "predec.->key()" (parameter) + weight of this edge
// As this will only be called once we calculate the weight
// of the edge "on the fly"
// Note: We have to pass the queue as we have to call keyDecreased :}
void relax( const Vertex* predecessor, PriorityQueue<Vertex>& queue );
// debugging
void dump( const TQCString& indent ) const;
private:
Edge( const Edge& rhs );
Edge& operator=( const Edge& rhs );
Vertex* m_vertex;
KoFilterEntry::Ptr m_filterEntry;
class Private;
Private* d;
};
/**
* An internal class representing a mime type (=node, vertex) in the filter graph.
* @internal
*/
class Vertex
{
public:
Vertex( const TQCString& mimeType );
~Vertex() {}
TQCString mimeType() const { return m_mimeType; }
// Current "weight" of the vertex - will be "relaxed" when
// running the shortest path algorithm. Returns true if it
// really has been "relaxed"
bool setKey( unsigned int key );
unsigned int key() const { return m_weight; }
// Can be used to set the key back to "Infinity" (UINT_MAX)
// and reset the predecessor of this vertex
void reset();
// Position in the heap, needed for a fast keyDecreased operation
void setIndex( int index ) { m_index=index; }
int index() const { return m_index; }
// predecessor on the way from the source to the destination,
// needed for the shortest path algorithm
void setPredecessor( const Vertex* predecessor ) { m_predecessor=predecessor; }
const Vertex* predecessor() const { return m_predecessor; }
// Adds an outgoing edge to the vertex, transfers ownership
void addEdge( const Edge* edge );
// Finds the lightest(!) edge pointing to the given vertex, if any (0 if not found)
// This means it will always search the whole list of edges
const Edge* findEdge( const Vertex* vertex ) const;
// This method is called when we need to relax all "our" edges.
// We need to pass the queue as we have to notify it about key changes - ugly :(
void relaxVertices( PriorityQueue<Vertex>& queue );
// debugging
void dump( const TQCString& indent ) const;
private:
Vertex( const Vertex& rhs );
Vertex& operator=( const Vertex& rhs );
TQPtrList<Edge> m_edges;
const Vertex* m_predecessor;
TQCString m_mimeType;
unsigned int m_weight; // "key" inside the queue
int m_index; // position inside the queue, needed for a fast keyDecreased()
class Private;
Private* d;
};
/**
* The main worker behind the scenes. Manages the creation of the graph,
* processing the information in it, and creating the filter chains.
* @internal
*/
class Graph
{
public:
Graph( const TQCString& from );
~Graph() {}
bool isValid() const { return m_graphValid; }
TQCString sourceMimeType() const { return m_from; }
void setSourceMimeType( const TQCString& from );
// Creates a chain from "from" to the "to" mimetype
// If the "to" mimetype isEmpty() then we try to find the
// closest KOffice mimetype and use that as destination.
// After such a search "to" will contain the dest. mimetype (return value)
// if the search was successful. Might return 0!
KoFilterChain::Ptr chain( const KoFilterManager* manager, TQCString& to ) const;
// debugging
void dump() const;
private:
Graph( const Graph& rhs );
Graph& operator=( const Graph& rhs );
void buildGraph();
void shortestPaths();
TQCString findKOfficePart() const;
TQAsciiDict<Vertex> m_vertices;
TQCString m_from;
bool m_graphValid;
class Private;
Private* d;
};
} // namespace KOffice
#endif // __koffice_filter_chain_h__