EmbeddedFile::EmbeddedFile(string const & file, string const & inzip_name,
bool embed, ParConstIterator const & pit)
: DocFileName(file, true), inzip_name_(inzip_name), embedded_(embed),
- valid_(true), par_it_(pit)
-{}
+ valid_(true), par_it_()
+{
+ if (pit != ParConstIterator())
+ par_it_.push_back(pit);
+}
string EmbeddedFile::embeddedFile(Buffer const * buf) const
}
-int const EmbeddedFile::parID() const
+void EmbeddedFile::addParIter(ParConstIterator const & pit)
{
- // some embedded file do not have a valid par iterator
- return par_it_ == ParConstIterator() ? 0 : par_it_->id();
+ par_it_.push_back(pit);
}
-void EmbeddedFile::setParIter(ParConstIterator const & pit)
+int EmbeddedFile::parID(int idx) const
{
- par_it_ = pit;
+ BOOST_ASSERT(idx < refCount());
+ // some embedded file do not have a valid par iterator
+ return par_it_[idx]->id();
}
string EmbeddedFile::availableFile(Buffer const * buf) const
{
- if (embedded_)
+ if (embedded())
return embeddedFile(buf);
else
return absFilename();
}
+void EmbeddedFile::invalidate()
+{
+ // Clear par_it_ because they will be registered again.
+ par_it_.clear();
+ valid_ = false;
+}
+
+
bool EmbeddedFile::extract(Buffer const * buf) const
{
- if (!embedded_)
- return true;
string ext_file = absFilename();
string emb_file = embeddedFile(buf);
- bool copyFile = false;
- // both files exist, are different
- if (fs::exists(ext_file) && fs::exists(emb_file)
- && sum(*this) != sum(FileName(emb_file))) {
- int const ret = Alert::prompt(
+
+ if (!fs::exists(emb_file))
+ return false;
+
+ // if external file already exists ...
+ if (fs::exists(ext_file)) {
+ // no need to copy if the files are the same
+ if (sum(*this) == sum(FileName(emb_file)))
+ return true;
+ // otherwise, ask if overwrite
+ int ret = Alert::prompt(
_("Overwrite external file?"),
bformat(_("External file %1$s already exists, do you want to overwrite it"),
from_utf8(ext_file)), 1, 1, _("&Overwrite"), _("&Cancel"));
- copyFile = ret == 0;
- }
- // copy file in the previous case, and a new case
- if (copyFile || (!fs::exists(ext_file) && fs::exists(emb_file))) {
- try {
- // need to make directory?
- string path = onlyPath(ext_file);
- if (!fs::is_directory(path))
- makedir(const_cast<char*>(path.c_str()), 0755);
- fs::copy_file(emb_file, ext_file, false);
+ if (ret != 0)
+ // if the user does not want to overwrite, we still consider it
+ // a successful operation.
return true;
- } catch (fs::filesystem_error const & fe) {
- Alert::error(_("Copy file failure"),
- bformat(_("Cannot copy file %1$s to %2$s.\n"
- "Please check whether the directory exists and is writeable."),
- from_utf8(emb_file), from_utf8(ext_file)));
- LYXERR(Debug::DEBUG) << "Fs error: " << fe.what() << endl;
- }
+ }
+ // copy file
+ try {
+ // need to make directory?
+ string path = onlyPath(ext_file);
+ if (!fs::is_directory(path))
+ makedir(const_cast<char*>(path.c_str()), 0755);
+ fs::copy_file(emb_file, ext_file, false);
+ return true;
+ } catch (fs::filesystem_error const & fe) {
+ Alert::error(_("Copy file failure"),
+ bformat(_("Cannot copy file %1$s to %2$s.\n"
+ "Please check whether the directory exists and is writeable."),
+ from_utf8(emb_file), from_utf8(ext_file)));
+ LYXERR(Debug::DEBUG) << "Fs error: " << fe.what() << endl;
}
return false;
}
-bool EmbeddedFile::update(Buffer const * buf) const
+bool EmbeddedFile::updateFromExternalFile(Buffer const * buf) const
{
string ext_file = absFilename();
string emb_file = embeddedFile(buf);
- bool copyFile = false;
- // both files exist, are different
- if (fs::exists(ext_file) && fs::exists(emb_file)
- && sum(*this) != sum(FileName(emb_file))) {
+
+ if (!fs::exists(ext_file))
+ return false;
+
+ // if embedded file already exists ...
+ if (fs::exists(emb_file)) {
+ // no need to copy if the files are the same
+ if (sum(*this) == sum(FileName(emb_file)))
+ return true;
+ // other wise, ask if overwrite
int const ret = Alert::prompt(
_("Update embedded file?"),
bformat(_("Embeddedl file %1$s already exists, do you want to overwrite it"),
from_utf8(ext_file)), 1, 1, _("&Overwrite"), _("&Cancel"));
- copyFile = ret == 0;
+ if (ret != 0)
+ // if the user does not want to overwrite, we still consider it
+ // a successful operation.
+ return true;
}
- // copy file in the previous case, and a new case
- if (copyFile || (fs::exists(ext_file) && !fs::exists(emb_file))) {
- try {
- // need to make directory?
- string path = onlyPath(emb_file);
- if (!fs::is_directory(path))
- makedir(const_cast<char*>(path.c_str()), 0755);
- fs::copy_file(ext_file, emb_file, false);
- } catch (fs::filesystem_error const & fe) {
- Alert::error(_("Copy file failure"),
- bformat(_("Cannot copy file %1$s to %2$s.\n"
- "Please check whether the directory exists and is writeable."),
- from_utf8(ext_file), from_utf8(emb_file)));
- LYXERR(Debug::DEBUG) << "Fs error: " << fe.what() << endl;
- return false;
- }
+ // copy file
+ try {
+ // need to make directory?
+ string path = onlyPath(emb_file);
+ if (!fs::is_directory(path))
+ makedir(const_cast<char*>(path.c_str()), 0755);
+ fs::copy_file(ext_file, emb_file, false);
+ return true;
+ } catch (fs::filesystem_error const & fe) {
+ Alert::error(_("Copy file failure"),
+ bformat(_("Cannot copy file %1$s to %2$s.\n"
+ "Please check whether the directory exists and is writeable."),
+ from_utf8(ext_file), from_utf8(emb_file)));
+ LYXERR(Debug::DEBUG) << "Fs error: " << fe.what() << endl;
}
- return true;
+ return false;
}
}
-void EmbeddedFiles::enable(bool flag)
+bool EmbeddedFiles::enable(bool flag)
{
if (enabled() != flag) {
- // if disable embedding, first extract all embedded files
- if (flag || (!flag && extractAll())) {
- // file will be changed
- buffer_->markDirty();
- buffer_->params().embedded = flag;
- }
+ // if enable, copy all files to temppath()
+ // if disable, extract all files
+ if ((flag && !updateFromExternalFile()) || (!flag && !extract()))
+ return false;
+ // if operation is successful
+ buffer_->markDirty();
+ buffer_->params().embedded = flag;
}
}
void EmbeddedFiles::registerFile(string const & filename,
bool embed, ParConstIterator const & pit)
{
+ // filename can be relative or absolute, translate to absolute filename
string abs_filename = makeAbsPath(filename, buffer_->filePath()).absFilename();
// try to find this file from the list
EmbeddedFileList::iterator it = file_list_.begin();
for (; it != it_end; ++it)
if (it->absFilename() == abs_filename || it->embeddedFile(buffer_) == abs_filename)
break;
- // find this filename
+ // find this filename, keep the original embedding status
if (it != file_list_.end()) {
- it->setParIter(pit);
- it->update(buffer_);
- it->setEmbed(true);
+ it->addParIter(pit);
+ // if the file is embedded, the embedded file should have exist
+ // check for this to ensure that our logic is correct
+ if (it->embedded())
+ BOOST_ASSERT(fs::exists(it->embeddedFile(buffer_)));
it->validate();
return;
}
+ // try to be more careful
file_list_.push_back(EmbeddedFile(abs_filename,
getInzipName(abs_filename), embed, pit));
+ // validate if things are OK
+ BOOST_ASSERT(fs::exists(file_list_.back().availableFile(buffer_)));
}
EmbeddedFileList::iterator it = file_list_.begin();
EmbeddedFileList::iterator it_end = file_list_.end();
for (; it != it_end; ++it)
- it->invalidate();
+ // we do not update items that are manually inserted
+ if (it->refCount() > 0)
+ it->invalidate();
ParIterator pit = buffer_->par_iterator_begin();
ParIterator pit_end = buffer_->par_iterator_end();
}
-bool EmbeddedFiles::extractAll() const
+bool EmbeddedFiles::extract() const
+{
+ EmbeddedFileList::const_iterator it = file_list_.begin();
+ EmbeddedFileList::const_iterator it_end = file_list_.end();
+ for (; it != it_end; ++it)
+ if (it->valid() && it->embedded())
+ if(!it->extract(buffer_))
+ return false;
+ return true;
+}
+
+
+bool EmbeddedFiles::updateFromExternalFile() const
{
EmbeddedFileList::const_iterator it = file_list_.begin();
EmbeddedFileList::const_iterator it_end = file_list_.end();
- // FIXME: the logic here is hard to decide, we should allow cancel for
- // 'do not overwrite' this file, and cancel for 'cancel extract all files'.
- // I am not sure how to do this now.
for (; it != it_end; ++it)
if (it->valid() && it->embedded())
- it->extract(buffer_);
+ if (!it->updateFromExternalFile(buffer_))
+ return false;
return true;
}
std::string availableFile(Buffer const * buf) const;
/// paragraph id
- void setParIter(ParConstIterator const & pit);
- int const parID() const;
+ void addParIter(ParConstIterator const & pit);
+ int parID(int idx) const;
+ /// Number of Insets this file item is referred
+ /// If refCount() == 0, this file must be manually inserted.
+ /// This fact is used by the update() function to skip updating
+ /// such items.
+ int refCount() const { return par_it_.size(); }
/// embedding status of this file
bool embedded() const { return embedded_; }
- /// set embedding status. update() should be called before this
- /// to sync the embedded file with external one.
+ /// set embedding status. updateFromExternal() should be called before this
+ /// to copy or sync the embedded file with external one.
bool setEmbed(bool embed) { embedded_ = embed; }
// A flag indicating whether or not this filename is valid.
// status setting untouched.
bool valid() const { return valid_; }
void validate() { valid_ = true; }
- void invalidate() { valid_ = false; }
+ void invalidate();
/// extract file, does not change embedding status
bool extract(Buffer const * buf) const;
/// update embedded file from external file, does not change embedding status
- bool update(Buffer const * buf) const;
+ bool updateFromExternalFile(Buffer const * buf) const;
private:
/// filename in zip file
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_;
+ /// Current position of the item, used to locate the files. Because one
+ /// file item can be referred by several Insets, a vector is used.
+ std::vector<ParConstIterator> par_it_;
};
/// return buffer params embedded flag
bool enabled() const;
- /// set buffer params embedded flag
- void enable(bool flag);
-
- /// add a file item
+ /// set buffer params embedded flag. Files will be updated or extracted
+ /// if such an operation fails, enable will fail.
+ bool enable(bool flag);
+
+ /// add a file item.
+ /* \param filename filename to add
+ * \param embed embedding status. For a new file item, this is always true.
+ * If the file already exists, this parameter is ignored.
+ * \param pit paragraph id.
+ */
void registerFile(std::string const & filename, bool embed = false,
ParConstIterator const & pit = ParConstIterator());
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;
+ /// extract all file items, used when disable embedding
+ bool extract() const;
+ /// update all files from external, used when enable embedding
+ bool updateFromExternalFile() const;
///
friend std::istream & operator>> (std::istream & is, EmbeddedFiles &);
#include "GuiEmbeddedFiles.h"
#include "debug.h"
+#include "support/convert.h"
+using std::string;
namespace lyx {
+
namespace frontend {
{
EmbeddedFiles & files = controller().embeddedFiles();
if (item->checkState() == Qt::Checked) {
+ if (files[filesLW->row(item)].embedded())
+ return;
controller().setEmbed(files[filesLW->row(item)], true);
controller().dispatchMessage("Embed file " + fromqstr(item->text()));
} else {
+ if (!files[filesLW->row(item)].embedded())
+ return;
controller().setEmbed(files[filesLW->row(item)], false);
controller().dispatchMessage("Stop embedding file " + fromqstr(item->text()));
}
fullpathLE->setEnabled(selection.size() == 1);
// try to find a common embedding status
- QList<QListWidgetItem*>::iterator it = selection.begin();
- QList<QListWidgetItem*>::iterator it_end = selection.end();
- // if the selection is not empty
- if (it != it_end) {
- int idx = filesLW->row(*it);
- fullpathLE->setText(toqstr(files[idx].absFilename()));
- controller().goTo(files[idx]);
- }
- // are the items all selected or unselected?
bool hasSelected = false;
bool hasUnselected = false;
+ QList<QListWidgetItem*>::iterator it = selection.begin();
+ QList<QListWidgetItem*>::iterator it_end = selection.end();
for (; it != it_end; ++it) {
if ((*it)->checkState() == Qt::Checked)
hasSelected = true;
}
-void GuiEmbeddedFilesDialog::on_filesLW_itemDoubleClicked()
+void GuiEmbeddedFilesDialog::on_filesLW_itemClicked(QListWidgetItem* item)
{
EmbeddedFiles & files = controller().embeddedFiles();
- QList<QListWidgetItem *> selection = filesLW->selectedItems();
- controller().view(files[filesLW->row(*selection.begin())]);
+ int idx = filesLW->row(item);
+ fullpathLE->setText(toqstr(files[idx].absFilename()));
+ if (files[idx].refCount() > 1) {
+ // if multiple insets are referred, click again will move
+ // to another inset
+ int k = item->data(Qt::UserRole).toInt();
+ controller().goTo(files[idx], k);
+ k = (k + 1) % files[idx].refCount();
+ item->setData(Qt::UserRole, k);
+ // update label
+ string label = files[idx].inzipName() + " ("
+ + convert<string>(k + 1) + "/"
+ + convert<string>(files[idx].refCount()) + ")";
+ item->setText(toqstr(label));
+ } else
+ controller().goTo(files[idx], 0);
+}
+
+
+void GuiEmbeddedFilesDialog::on_filesLW_itemDoubleClicked(QListWidgetItem* item)
+{
+ EmbeddedFiles & files = controller().embeddedFiles();
+ controller().view(files[filesLW->row(item)]);
}
EmbeddedFiles::EmbeddedFileList::const_iterator it = files.begin();
EmbeddedFiles::EmbeddedFileList::const_iterator it_end = files.end();
for (; it != it_end; ++it) {
- QListWidgetItem * item = new QListWidgetItem(toqstr(it->inzipName()));
+ string label = it->inzipName();
+ if (it->refCount() > 1)
+ label += " (1/" + convert<string>(it->refCount()) + ")";
+ QListWidgetItem * item = new QListWidgetItem(toqstr(label));
Qt::ItemFlags flag = Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
if (it->valid())
flag |= Qt::ItemIsEnabled;
item->setCheckState(Qt::Checked);
else
item->setCheckState(Qt::Unchecked);
+ // index of the currently used ParConstIterator
+ item->setData(Qt::UserRole, 0);
filesLW->addItem(item);
}
}