]> git.lyx.org Git - lyx.git/blobdiff - src/EmbeddedFiles.h
Embedding: saving inzip name to .lyx file so that embedded files can always be found...
[lyx.git] / src / EmbeddedFiles.h
index 9c63c2d8d5d47194e65144bc6654e3e1fd2e2779..b0d719ba858ce0bddb3cfe6424571819797abead 100644 (file)
 
 #include "support/FileName.h"
 
+#include <string>
 #include <vector>
-#include <utility>
-
-#include "ParIterator.h"
-#include "Paragraph.h"
 
 /**
 
@@ -30,15 +27,23 @@ an 'Embedded Files' feature of lyx.
 Expected features:
 =========================
 
-1. With embedding enabled (disabled by default), .lyx file can embed graphics,
-listings, bib file etc.
+1. Bundled .lyx file can embed graphics, listings, bib file etc. The bundle
+format is used when Document->Save in bundled format is selected.
+
+2. Embedded file.lyx file is a zip file, with content.lyx and embedded files. 
+
+3. The embedding status of embedded files can be set at the inset level,
+or from Document->Settings->Embedded Files.
+
+4. Extra files such as .cls and .layout can be embedded from Document->
+Settings->Embedded Files->Extra Files.
 
-2. Embedded file.lyx file is a zip file, with file.lyx, manifest.txt
-and embedded files. 
+5. When Document->Save in bundled format is selected, all embedded files
+become bundled. Changes to the external version of this file does not
+affect the output of the .lyx file.
 
-3. An embedding dialog is provided to change embedding status (buffer
-level or individual embedded files), manually embed, extract, view
-or edit files.
+6. When Document->Save in bundled format is unchecked, all embedded files
+are copied to their original locations.
 
 Overall, this feature allows two ways of editing a .lyx file
 
@@ -51,166 +56,163 @@ be embedded. These embedded files can be viewed or edited through
 the embedding dialog. This file can be shared with others more
 easily. 
 
-Format a anb b can be converted easily, by enable/disable embedding. Diabling
-embedding is also called unpacking because all embedded files will be copied
-to their original locations.
+Format a and b can be converted easily, by packing/unpacking a .lyx file.
+
+NOTE: With current implementation, files with absolute filenames (not in
+or deeper under the current document directory) can not be embedded.
 
 Implementation:
 ======================
 
 1. An EmbeddedFiles class is implemented to keep the embedded files (
 class EmbeddedFile). (c.f. src/EmbeddedFiles.[h|cpp])
-This class keeps a manifest that has
-  a. external relative filename
-  b. inzip filename. It is the relative path name if the embedded file is
-    in or under the document directory, or file name otherwise. Name aliasing
-    is used if two external files share the same name.
-  c. embedding status.
-It also provides functions to
-  a. manipulate manifest
-  b. scan a buffer for embeddable files
-  c. determine which file to use according to embedding status
 
 2. When a file is saved, it is scanned for embedded files. (c.f.
 EmbeddedFiles::update(), Inset::registerEmbeddedFiles()).
 
-3. When a lyx file file.lyx is saved, it is save to tmppath() first.
-Embedded files are compressed along with file.lyx and a manifest.txt. 
+3. When a lyx file file.lyx is saved, it is save to tmppath()/content.lyx
+first. Embedded files are compressed along with content.lyx.
 If embedding is disabled, file.lyx is saved in the usual pure-text form.
-(c.f. Buffer::writeFile(), EmbeddedFiles::write())
+(c.f. Buffer::writeFile(), EmbeddedFiles::writeFile())
 
 4. When a lyx file.lyx file is opened, if it is a zip file, it is
-decompressed to tmppath(). If manifest.txt and file.lyx exists in
-tmppath(), the manifest is read to buffer, and tmppath()/file.lyx is
-read as usual. If file.lyx is not a zip file, it is read as usual.
+decompressed to tmppath() and tmppath()/content.lyx is read as usual.
 (c.f. bool Buffer::readFile())
 
-5. A menu item Document -> Embedded Files is provided to open
-a embedding dialog. It handles a EmbddedFiles point directly.
-From this dialog, a user can disable embedding, change embedding status,
-or embed other files, extract, view, edit files.
+5. A menu item Document -> Save in bundled format is provided to pack/unpack
+a .lyx file.
 
 6. If embedding of a .lyx file with embedded files is disabled, all its
 embedded files are copied to their respective external filenames. This
 is why external filename will exist even if a file is at "EMBEDDED" status.
 
-7. Individual embeddable insets should find ways to handle embedded files.
-InsetGraphics replace params().filename with its temppath()/inzipname version
-when the inset is created. The filename appears as /tmp/..../inzipname
-when lyx runs. When params().filename is saved, lyx checks if this is an
-embedded file (check path == temppath()), if so, save filename() instead.
-(c.f. InsetGraphic::read(), InsetGraphics::edit(), InsetGraphicsParams::write())
-
-
 */
 
 namespace lyx {
 
 class Buffer;
+class Inset;
+class Lexer;
+class ErrorList;
 
 class EmbeddedFile : public support::DocFileName
 {
 public:
-       EmbeddedFile(std::string const & file, std::string const & inzip_name,
-               bool embedded, ParConstIterator const & pit);
-
-       /// filename in the zip file, usually the relative path
+       EmbeddedFile(std::string const & file = std::string(),
+               std::string const & buffer_path = std::string());
+       
+       /// set filename and inzipName.
+       /**
+        * NOTE: inzip_name_ is not unique across operation systems and is not 
+        * guaranteed to be the same across different versions of lyx.
+        * inzip_name_ will be saved to the lyx file, and is used to indicate 
+        * whether or not a file is embedded, and where the embedded file is in
+        * the bundled file. However, the embedded file will be renamed to the 
+        * name set here when an EmbeddedFile is enabled. It is therefore
+        * safe to change the naming scheme here.
+        *
+        * NOTE that this treatment does not welcome an UUID solution because
+        * all embedded files will have to be renamed when an embedded file is
+        * opened. It is of course possible to use saved inzipname, but that is
+        * not easy. For example, when a new EmbeddedFile is created with the same
+        * file as an old one, it needs to be synced to the old inzipname...
+       **/
+       void set(std::string const & filename, std::string const & buffer_path);
+       /** Set the inzip name of an EmbeddedFile, which should be the name
+        *  of an actual embedded file on disk. When an EmbeddedFile is enabled,
+        *  this file will be renamed to the default inzipName if needed. 
+        */
+       void setInzipName(std::string const & name);
+
+       /// filename in the zip file, which is the relative path
        std::string inzipName() const { return inzip_name_; }
+
        /// embedded file, equals to temppath()/inzipName()
-       std::string embeddedFile(Buffer const * buf) const;
+       std::string embeddedFile() const;
        /// embeddedFile() or absFilename() depending on embedding status
-       std::string availableFile(Buffer const * buf) const;
+       /// and whether or not embedding is enabled.
+       FileName availableFile() const;
+       /// 
+       std::string latexFilename(std::string const & buffer_path) const;
 
-       /// paragraph id
-       void setParIter(ParConstIterator const & pit);
-       int const parID() const;
+       /// add an inset that refers to this file
+       void addInset(Inset const * inset);
+       int refCount() const { return inset_list_.size(); }
 
        /// embedding status of this file
        bool embedded() const { return embedded_; }
-
-       // A flag indicating whether or not this filename is valid.
-       // When lyx runs, InsetGraphics etc may be added or removed so filename
-       // maybe obsolete. In Buffer::updateEmbeddedFiles, the EmbeddedFiles is first
-       // invalidated (c.f. invalidate()), and all insets are asked to register
-       // embedded files. In this way, EmbeddedFileList will be refreshed, with
-       // status setting untouched.
-       bool valid() const { return valid_; }
-       void validate() { valid_ = true; }
-       void invalidate() {     valid_ = false; }
+       /// set embedding status. updateFromExternal() should be called before this
+       /// to copy or sync the embedded file with external one.
+       void setEmbed(bool embed);
+
+       /// whether or not embedding is enabled in the current buffer
+       bool enabled() const { return temp_path_ != ""; }
+       /// enable embedding of this file
+       void enable(bool flag, Buffer const * buf);
+
+       /// extract file, does not change embedding status
+       bool extract() const;
+       /// update embedded file from external file, does not change embedding status
+       bool updateFromExternalFile() const;
        ///
-       bool extract(Buffer const * buf) const;
-       ///
-       bool embed(Buffer const * buf);
+       /// After the embedding status is changed, update all insets related
+       /// to this file item. For example, a graphic inset may need to monitor
+       /// embedded file instead of external file. To make sure inset pointers 
+       /// are up to date, please make sure there is no modification to the
+       /// document between EmbeddedFiles::update() and this function.
+       void updateInsets(Buffer const * buf) const;
+
+       /// Check readability of availableFile
+       bool isReadableFile() const;
+       /// Calculate checksum of availableFile
+       unsigned long checksum() const;
 
+private:
+       // calculate inzip_name_ from filename
+       std::string calcInzipName(std::string const & buffer_path);
+       // move an embedded disk file with an existing inzip_name_ to 
+       // an calculated inzip_name_
+       void syncInzipFile(std::string const & buffer_path);
+       
 private:
        /// filename in zip file
        std::string inzip_name_;
        /// the status of this docfile
        bool embedded_;
-       ///
-       bool valid_;
-       /// Current position of the item, used to locate the files
-       /// A figure may be referred by several items. In this case
-       /// only the last location is recorded.
-       ParConstIterator par_it_;
+       /// Insets that contains this file item. Because a 
+       /// file item can be referred by several Insets, a vector is used.
+       std::vector<Inset const *> inset_list_;
+       /// Embedded file needs to know whether enbedding is enabled,
+       /// and where is the lyx temporary directory. Such information can
+       /// be retrived from a buffer, but a buffer is not always available when
+       /// an EmbeddedFile is used.
+       std::string temp_path_;
 };
 
 
-class EmbeddedFiles {
-public:
-       typedef std::vector<EmbeddedFile> EmbeddedFileList;
-public:
-       ///
-       EmbeddedFiles(Buffer * buffer = NULL): file_list_(), buffer_(buffer) {}
-       ///
-       ~EmbeddedFiles() {}
+bool operator==(EmbeddedFile const & lhs, EmbeddedFile const & rhs);
+bool operator!=(EmbeddedFile const & lhs, EmbeddedFile const & rhs);
 
-       /// return buffer params embedded flag
-       bool enabled() const;
-       /// set buffer params embedded flag
-       void enable(bool flag);
 
-       /// add a file item
-       void registerFile(std::string const & filename, bool embed = false,
-               ParConstIterator const & pit = ParConstIterator());
+class EmbeddedFileList : public std::vector<EmbeddedFile> {
+public:
+       /// set buffer params embedded flag. Files will be updated or extracted
+       /// if such an operation fails, enable will fail.
+       void enable(bool flag, Buffer & buffer);
+
+       /// add a file item.
+       /* \param file Embedded file to add
+        * \param inset Inset pointer
+        */
+       void registerFile(EmbeddedFile const & file, Inset const * inset, Buffer const & buffer);
 
        /// scan the buffer and get a list of EmbeddedFile
-       void update();
+       void update(Buffer const & buffer);
 
        /// write a zip file
-       bool write(support::DocFileName const & filename);
-
-       void clear() { file_list_.clear(); }
-
-       ///
-       EmbeddedFile & operator[](size_t idx) { return *(file_list_.begin() + idx); }
-       EmbeddedFile const & operator[](size_t idx) const { return *(file_list_.begin() + idx); }
-       ///
-       EmbeddedFileList::iterator begin() { return file_list_.begin(); }
-       EmbeddedFileList::iterator end() { return file_list_.end(); }
-       EmbeddedFileList::const_iterator begin() const { return file_list_.begin(); }
-       EmbeddedFileList::const_iterator end() const { return file_list_.end(); }
-       // try to locate filename, using either absFilename() or embeddedFile()
-       EmbeddedFileList::const_iterator find(std::string filename) const;
-       ///
-       bool extractAll() const;
-       ///
-       friend std::istream & operator>> (std::istream & is, EmbeddedFiles &);
-
-       friend std::ostream & operator<< (std::ostream & os, EmbeddedFiles const &);
-private:
-       /// get a unique inzip name
-       std::string const getInzipName(std::string const & name);
-       /// list of embedded files
-       EmbeddedFileList file_list_;
-       ///
-       Buffer * buffer_;
+       bool writeFile(support::DocFileName const & filename, Buffer const & buffer);
 };
 
+} // namespace lyx
 
-std::istream & operator>> (std::istream & is, EmbeddedFiles &);
-
-std::ostream & operator<< (std::ostream & os, EmbeddedFiles const &);
-
-}
 #endif