|
|
|
/***************************************************************************
|
|
|
|
copyright : (C) 2001-2006 by Robby Stephenson
|
|
|
|
email : robby@periapsis.org
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of version 2 of the GNU General Public License as *
|
|
|
|
* published by the Free Software Foundation; *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "document.h"
|
|
|
|
#include "mainwindow.h" // needed for calling fileSave()
|
|
|
|
#include "collectionfactory.h"
|
|
|
|
#include "translators/tellicoimporter.h"
|
|
|
|
#include "translators/tellicosaximporter.h"
|
|
|
|
#include "translators/tellicozipexporter.h"
|
|
|
|
#include "translators/tellicoxmlexporter.h"
|
|
|
|
#include "collection.h"
|
|
|
|
#include "filehandler.h"
|
|
|
|
#include "controller.h"
|
|
|
|
#include "borrower.h"
|
|
|
|
#include "tellico_kernel.h"
|
|
|
|
#include "latin1literal.h"
|
|
|
|
#include "tellico_debug.h"
|
|
|
|
#include "imagefactory.h"
|
|
|
|
#include "image.h"
|
|
|
|
#include "stringset.h"
|
|
|
|
#include "progressmanager.h"
|
|
|
|
#include "core/tellico_config.h"
|
|
|
|
|
|
|
|
#include <tdemessagebox.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tdeglobal.h>
|
|
|
|
#include <tdeapplication.h>
|
|
|
|
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
|
|
|
|
// use a vector so we can use a sort functor
|
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
using Tellico::Data::Document;
|
|
|
|
Document* Document::s_self = 0;
|
|
|
|
|
|
|
|
Document::Document() : TQObject(), m_coll(0), m_isModified(false),
|
|
|
|
m_loadAllImages(false), m_validFile(false), m_importer(0), m_cancelImageWriting(false),
|
|
|
|
m_fileFormat(Import::TellicoImporter::Unknown) {
|
|
|
|
m_allImagesOnDisk = Config::imageLocation() != Config::ImagesInFile;
|
|
|
|
newDocument(Collection::Book);
|
|
|
|
}
|
|
|
|
|
|
|
|
Document::~Document() {
|
|
|
|
delete m_importer;
|
|
|
|
m_importer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Tellico::Data::CollPtr Document::collection() const {
|
|
|
|
return m_coll;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::setURL(const KURL& url_) {
|
|
|
|
m_url = url_;
|
|
|
|
if(m_url.fileName() != i18n("Untitled")) {
|
|
|
|
ImageFactory::setLocalDirectory(m_url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::slotSetModified(bool m_/*=true*/) {
|
|
|
|
m_isModified = m_;
|
|
|
|
emit signalModified(m_isModified);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::slotDocumentRestored() {
|
|
|
|
slotSetModified(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Document::newDocument(int type_) {
|
|
|
|
// kdDebug() << "Document::newDocument()" << endl;
|
|
|
|
delete m_importer;
|
|
|
|
m_importer = 0;
|
|
|
|
deleteContents();
|
|
|
|
|
|
|
|
m_coll = CollectionFactory::collection(static_cast<Collection::Type>(type_), true);
|
|
|
|
m_coll->setTrackGroups(true);
|
|
|
|
|
|
|
|
Kernel::self()->resetHistory();
|
|
|
|
Controller::self()->slotCollectionAdded(m_coll);
|
|
|
|
|
|
|
|
slotSetModified(false);
|
|
|
|
KURL url;
|
|
|
|
url.setFileName(i18n("Untitled"));
|
|
|
|
setURL(url);
|
|
|
|
m_validFile = false;
|
|
|
|
m_fileFormat = Import::TellicoImporter::Unknown;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Document::openDocument(const KURL& url_) {
|
|
|
|
myLog() << "Document::openDocument() - " << url_.prettyURL() << endl;
|
|
|
|
|
|
|
|
m_loadAllImages = false;
|
|
|
|
// delayed image loading only works for local files
|
|
|
|
if(!url_.isLocalFile()) {
|
|
|
|
m_loadAllImages = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete m_importer;
|
|
|
|
#ifdef SAX_SUPPORT
|
|
|
|
myLog() << "Document::openDocument() - using SAX loader" << endl;
|
|
|
|
m_importer = new Import::TellicoSaxImporter(url_, m_loadAllImages);
|
|
|
|
#else
|
|
|
|
m_importer = new Import::TellicoImporter(url_, m_loadAllImages);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CollPtr coll = m_importer->collection();
|
|
|
|
// delayed image loading only works for zip files
|
|
|
|
// format is only known AFTER collection() is called
|
|
|
|
|
|
|
|
m_fileFormat = m_importer->format();
|
|
|
|
m_allImagesOnDisk = !m_importer->hasImages();
|
|
|
|
if(!m_importer->hasImages() || m_fileFormat != Import::TellicoImporter::Zip) {
|
|
|
|
m_loadAllImages = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!coll) {
|
|
|
|
// myDebug() << "Document::openDocument() - returning false" << endl;
|
|
|
|
Kernel::self()->sorry(m_importer->statusMessage());
|
|
|
|
m_validFile = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
deleteContents();
|
|
|
|
m_coll = coll;
|
|
|
|
m_coll->setTrackGroups(true);
|
|
|
|
setURL(url_);
|
|
|
|
m_validFile = true;
|
|
|
|
|
|
|
|
Kernel::self()->resetHistory();
|
|
|
|
Controller::self()->slotCollectionAdded(m_coll);
|
|
|
|
|
|
|
|
// m_importer might have been deleted?
|
|
|
|
slotSetModified(m_importer && m_importer->modifiedOriginal());
|
|
|
|
// if(pruneImages()) {
|
|
|
|
// slotSetModified(true);
|
|
|
|
// }
|
|
|
|
if(m_importer->hasImages()) {
|
|
|
|
m_cancelImageWriting = false;
|
|
|
|
TQTimer::singleShot(500, this, TQT_SLOT(slotLoadAllImages()));
|
|
|
|
} else {
|
|
|
|
emit signalCollectionImagesLoaded(m_coll);
|
|
|
|
m_importer->deleteLater();
|
|
|
|
m_importer = 0;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Document::saveModified() {
|
|
|
|
bool completed = true;
|
|
|
|
|
|
|
|
if(m_isModified) {
|
|
|
|
MainWindow* app = static_cast<MainWindow*>(Kernel::self()->widget());
|
|
|
|
TQString str = i18n("The current file has been modified.\n"
|
|
|
|
"Do you want to save it?");
|
|
|
|
int want_save = KMessageBox::warningYesNoCancel(Kernel::self()->widget(), str, i18n("Unsaved Changes"),
|
|
|
|
KStdGuiItem::save(), KStdGuiItem::discard());
|
|
|
|
switch(want_save) {
|
|
|
|
case KMessageBox::Yes:
|
|
|
|
completed = app->fileSave();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KMessageBox::No:
|
|
|
|
slotSetModified(false);
|
|
|
|
completed = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KMessageBox::Cancel:
|
|
|
|
default:
|
|
|
|
completed = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return completed;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Document::saveDocument(const KURL& url_) {
|
|
|
|
if(!FileHandler::queryExists(url_)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// DEBUG_BLOCK;
|
|
|
|
|
|
|
|
// in case we're still loading images, give that a chance to cancel
|
|
|
|
m_cancelImageWriting = true;
|
|
|
|
kapp->processEvents();
|
|
|
|
|
|
|
|
ProgressItem& item = ProgressManager::self()->newProgressItem(this, i18n("Saving file..."), false);
|
|
|
|
ProgressItem::Done done(this);
|
|
|
|
|
|
|
|
// will always save as zip file, no matter if has images or not
|
|
|
|
int imageLocation = Config::imageLocation();
|
|
|
|
bool includeImages = imageLocation == Config::ImagesInFile;
|
|
|
|
int totalSteps;
|
|
|
|
// write all images to disk cache if needed
|
|
|
|
// have to do this before executing exporter in case
|
|
|
|
// the user changed the imageInFile setting from Yes to No, in which
|
|
|
|
// case saving will over write the old file that has the images in it!
|
|
|
|
if(includeImages) {
|
|
|
|
totalSteps = 10;
|
|
|
|
item.setTotalSteps(10);
|
|
|
|
// since TellicoZipExporter uses 100 steps, then it will get 100/110 of the total progress
|
|
|
|
} else {
|
|
|
|
totalSteps = 100;
|
|
|
|
item.setTotalSteps(100);
|
|
|
|
m_cancelImageWriting = false;
|
|
|
|
writeAllImages(imageLocation == Config::ImagesInAppDir ? ImageFactory::DataDir : ImageFactory::LocalDir, url_);
|
|
|
|
}
|
|
|
|
Export::Exporter* exporter;
|
|
|
|
if(m_fileFormat == Import::TellicoImporter::XML) {
|
|
|
|
exporter = new Export::TellicoXMLExporter();
|
|
|
|
static_cast<Export::TellicoXMLExporter*>(exporter)->setIncludeImages(includeImages);
|
|
|
|
} else {
|
|
|
|
exporter = new Export::TellicoZipExporter();
|
|
|
|
static_cast<Export::TellicoZipExporter*>(exporter)->setIncludeImages(includeImages);
|
|
|
|
}
|
|
|
|
item.setProgress(int(0.8*totalSteps));
|
|
|
|
exporter->setEntries(m_coll->entries());
|
|
|
|
exporter->setURL(url_);
|
|
|
|
// since we already asked about overwriting the file, force the save
|
|
|
|
long opt = exporter->options() | Export::ExportForce | Export::ExportProgress;
|
|
|
|
// only write the image sizes if they're known already
|
|
|
|
opt &= ~Export::ExportImageSize;
|
|
|
|
exporter->setOptions(opt);
|
|
|
|
bool success = exporter->exec();
|
|
|
|
item.setProgress(int(0.9*totalSteps));
|
|
|
|
|
|
|
|
if(success) {
|
|
|
|
Kernel::self()->resetHistory();
|
|
|
|
setURL(url_);
|
|
|
|
// if successful, doc is no longer modified
|
|
|
|
slotSetModified(false);
|
|
|
|
} else {
|
|
|
|
myDebug() << "Document::saveDocument() - not successful saving to " << url_.prettyURL() << endl;
|
|
|
|
}
|
|
|
|
delete exporter;
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Document::closeDocument() {
|
|
|
|
delete m_importer;
|
|
|
|
m_importer = 0;
|
|
|
|
deleteContents();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::deleteContents() {
|
|
|
|
if(m_coll) {
|
|
|
|
Controller::self()->slotCollectionDeleted(m_coll);
|
|
|
|
}
|
|
|
|
// don't delete the m_importer here, bad things will happen
|
|
|
|
|
|
|
|
// since the collection holds a pointer to each entry and each entry
|
|
|
|
// hold a pointer to the collection, and they're both sharedptrs,
|
|
|
|
// neither will ever get deleted, unless the entries are removed from the collection
|
|
|
|
if(m_coll) {
|
|
|
|
m_coll->clear();
|
|
|
|
}
|
|
|
|
m_coll = 0; // old collection gets deleted as a TDESharedPtr
|
|
|
|
m_cancelImageWriting = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::appendCollection(CollPtr coll_) {
|
|
|
|
if(!coll_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_coll->blockSignals(true);
|
|
|
|
Data::FieldVec fields = coll_->fields();
|
|
|
|
for(FieldVec::Iterator field = fields.begin(); field != fields.end(); ++field) {
|
|
|
|
m_coll->mergeField(field);
|
|
|
|
}
|
|
|
|
|
|
|
|
EntryVec entries = coll_->entries();
|
|
|
|
for(EntryVec::Iterator entry = entries.begin(); entry != entries.end(); ++entry) {
|
|
|
|
Data::EntryPtr newEntry = new Data::Entry(*entry);
|
|
|
|
newEntry->setCollection(m_coll);
|
|
|
|
}
|
|
|
|
m_coll->addEntries(entries);
|
|
|
|
// TODO: merge filters and loans
|
|
|
|
m_coll->blockSignals(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
Tellico::Data::MergePair Document::mergeCollection(CollPtr coll_) {
|
|
|
|
MergePair pair;
|
|
|
|
if(!coll_) {
|
|
|
|
return pair;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_coll->blockSignals(true);
|
|
|
|
Data::FieldVec fields = coll_->fields();
|
|
|
|
for(FieldVec::Iterator field = fields.begin(); field != fields.end(); ++field) {
|
|
|
|
m_coll->mergeField(field);
|
|
|
|
}
|
|
|
|
|
|
|
|
EntryVec currEntries = m_coll->entries();
|
|
|
|
EntryVec newEntries = coll_->entries();
|
|
|
|
for(EntryVec::Iterator newIt = newEntries.begin(); newIt != newEntries.end(); ++newIt) {
|
|
|
|
int bestMatch = 0;
|
|
|
|
Data::EntryPtr matchEntry;
|
|
|
|
for(EntryVec::Iterator currIt = currEntries.begin(); currIt != currEntries.end(); ++currIt) {
|
|
|
|
int match = m_coll->sameEntry(&*currIt, &*newIt);
|
|
|
|
if(match >= Collection::ENTRY_PERFECT_MATCH) {
|
|
|
|
matchEntry = currIt;
|
|
|
|
break;
|
|
|
|
} else if(match >= Collection::ENTRY_GOOD_MATCH && match > bestMatch) {
|
|
|
|
bestMatch = match;
|
|
|
|
matchEntry = currIt;
|
|
|
|
// don't break, keep looking for better one
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(matchEntry) {
|
|
|
|
m_coll->mergeEntry(matchEntry, &*newIt, false /*overwrite*/);
|
|
|
|
} else {
|
|
|
|
Data::EntryPtr e = new Data::Entry(*newIt);
|
|
|
|
e->setCollection(m_coll);
|
|
|
|
// keep track of which entries got added
|
|
|
|
pair.first.append(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_coll->addEntries(pair.first);
|
|
|
|
// TODO: merge filters and loans
|
|
|
|
m_coll->blockSignals(false);
|
|
|
|
return pair;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::replaceCollection(CollPtr coll_) {
|
|
|
|
if(!coll_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// kdDebug() << "Document::replaceCollection()" << endl;
|
|
|
|
|
|
|
|
KURL url;
|
|
|
|
url.setFileName(i18n("Untitled"));
|
|
|
|
setURL(url);
|
|
|
|
m_validFile = false;
|
|
|
|
|
|
|
|
// the collection gets cleared by the CollectionCommand that called this function
|
|
|
|
// no need to do it here
|
|
|
|
|
|
|
|
m_coll = coll_;
|
|
|
|
m_coll->setTrackGroups(true);
|
|
|
|
m_cancelImageWriting = true;
|
|
|
|
// CollectionCommand takes care of calling Controller signals
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::unAppendCollection(CollPtr coll_, FieldVec origFields_) {
|
|
|
|
if(!coll_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_coll->blockSignals(true);
|
|
|
|
|
|
|
|
StringSet origFieldNames;
|
|
|
|
for(FieldVec::Iterator field = origFields_.begin(); field != origFields_.end(); ++field) {
|
|
|
|
m_coll->modifyField(field);
|
|
|
|
origFieldNames.add(field->name());
|
|
|
|
}
|
|
|
|
|
|
|
|
EntryVec entries = coll_->entries();
|
|
|
|
for(EntryVec::Iterator entry = entries.begin(); entry != entries.end(); ++entry) {
|
|
|
|
// probably don't need to do this, but on the safe side...
|
|
|
|
entry->setCollection(coll_);
|
|
|
|
}
|
|
|
|
m_coll->removeEntries(entries);
|
|
|
|
|
|
|
|
// since Collection::removeField() iterates over all entries to reset the value of the field
|
|
|
|
// don't removeField() until after removeEntry() is done
|
|
|
|
FieldVec currFields = m_coll->fields();
|
|
|
|
for(FieldVec::Iterator field = currFields.begin(); field != currFields.end(); ++field) {
|
|
|
|
if(!origFieldNames.has(field->name())) {
|
|
|
|
m_coll->removeField(field);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_coll->blockSignals(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::unMergeCollection(CollPtr coll_, FieldVec origFields_, MergePair entryPair_) {
|
|
|
|
if(!coll_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_coll->blockSignals(true);
|
|
|
|
|
|
|
|
TQStringList origFieldNames;
|
|
|
|
for(FieldVec::Iterator field = origFields_.begin(); field != origFields_.end(); ++field) {
|
|
|
|
m_coll->modifyField(field);
|
|
|
|
origFieldNames << field->name();
|
|
|
|
}
|
|
|
|
|
|
|
|
// first item in pair are the entries added by the operation, remove them
|
|
|
|
EntryVec entries = entryPair_.first;
|
|
|
|
m_coll->removeEntries(entries);
|
|
|
|
|
|
|
|
// second item in pair are the entries which got modified by the original merge command
|
|
|
|
const TQString track = TQString::fromLatin1("track");
|
|
|
|
PairVector trackChanges = entryPair_.second;
|
|
|
|
// need to go through them in reverse since one entry may have been modified multiple times
|
|
|
|
// first item in the pair is the entry pointer
|
|
|
|
// second item is the old value of the track field
|
|
|
|
for(int i = trackChanges.count()-1; i >= 0; --i) {
|
|
|
|
trackChanges[i].first->setField(track, trackChanges[i].second);
|
|
|
|
}
|
|
|
|
|
|
|
|
// since Collection::removeField() iterates over all entries to reset the value of the field
|
|
|
|
// don't removeField() until after removeEntry() is done
|
|
|
|
FieldVec currFields = m_coll->fields();
|
|
|
|
for(FieldVec::Iterator field = currFields.begin(); field != currFields.end(); ++field) {
|
|
|
|
if(origFieldNames.findIndex(field->name()) == -1) {
|
|
|
|
m_coll->removeField(field);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_coll->blockSignals(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Document::isEmpty() const {
|
|
|
|
//an empty doc may contain a collection, but no entries
|
|
|
|
return (!m_coll || m_coll->entries().isEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Document::loadImage(const TQString& id_) {
|
|
|
|
// myLog() << "Document::loadImage() - id = " << id_ << endl;
|
|
|
|
if(!m_coll) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool b = !m_loadAllImages && m_validFile && m_importer && m_importer->loadImage(id_);
|
|
|
|
if(b) {
|
|
|
|
m_allImagesOnDisk = false;
|
|
|
|
}
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Document::loadAllImagesNow() const {
|
|
|
|
// myLog() << "Document::loadAllImagesNow()" << endl;
|
|
|
|
if(!m_coll || !m_validFile) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(m_loadAllImages) {
|
|
|
|
myDebug() << "Document::loadAllImagesNow() - all valid images should already be loaded!" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return Import::TellicoImporter::loadAllImages(m_url);
|
|
|
|
}
|
|
|
|
|
|
|
|
Tellico::Data::EntryVec Document::filteredEntries(Filter::Ptr filter_) const {
|
|
|
|
Data::EntryVec matches;
|
|
|
|
Data::EntryVec entries = m_coll->entries();
|
|
|
|
for(EntryVec::Iterator it = entries.begin(); it != entries.end(); ++it) {
|
|
|
|
if(filter_->matches(it.data())) {
|
|
|
|
matches.append(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return matches;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::checkOutEntry(Data::EntryPtr entry_) {
|
|
|
|
if(!entry_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQString loaned = TQString::fromLatin1("loaned");
|
|
|
|
if(!m_coll->hasField(loaned)) {
|
|
|
|
FieldPtr f = new Field(loaned, i18n("Loaned"), Field::Bool);
|
|
|
|
f->setFlags(Field::AllowGrouped);
|
|
|
|
f->setCategory(i18n("Personal"));
|
|
|
|
m_coll->addField(f);
|
|
|
|
}
|
|
|
|
entry_->setField(loaned, TQString::fromLatin1("true"));
|
|
|
|
EntryVec vec;
|
|
|
|
vec.append(entry_);
|
|
|
|
m_coll->updateDicts(vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::checkInEntry(Data::EntryPtr entry_) {
|
|
|
|
if(!entry_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQString loaned = TQString::fromLatin1("loaned");
|
|
|
|
if(!m_coll->hasField(loaned)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
entry_->setField(loaned, TQString());
|
|
|
|
m_coll->updateDicts(EntryVec(entry_));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::renameCollection(const TQString& newTitle_) {
|
|
|
|
m_coll->setTitle(newTitle_);
|
|
|
|
}
|
|
|
|
|
|
|
|
// this only gets called when a zip file with images is opened
|
|
|
|
// by loading every image, it gets pulled out of the zip file and
|
|
|
|
// copied to disk. then the zip file can be closed and not retained in memory
|
|
|
|
void Document::slotLoadAllImages() {
|
|
|
|
TQString id;
|
|
|
|
StringSet images;
|
|
|
|
Data::EntryVec entries = m_coll->entries();
|
|
|
|
Data::FieldVec imageFields = m_coll->imageFields();
|
|
|
|
for(Data::EntryVec::Iterator entry = entries.begin(); entry != entries.end(); ++entry) {
|
|
|
|
for(Data::FieldVec::Iterator field = imageFields.begin(); field != imageFields.end() && !m_cancelImageWriting; ++field) {
|
|
|
|
id = entry->field(field);
|
|
|
|
if(id.isEmpty() || images.has(id)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// this is the early loading, so just by calling imageById()
|
|
|
|
// the image gets sucked from the zip file and written to disk
|
|
|
|
//by ImageFactory::imageById()
|
|
|
|
if(ImageFactory::imageById(id).isNull()) {
|
|
|
|
myDebug() << "Document::slotLoadAllImages() - entry title: " << entry->title() << endl;
|
|
|
|
}
|
|
|
|
images.add(id);
|
|
|
|
}
|
|
|
|
if(m_cancelImageWriting) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// stay responsive, do this in the background
|
|
|
|
kapp->processEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_cancelImageWriting) {
|
|
|
|
myLog() << "Document::slotLoadAllImages() - cancel image writing" << endl;
|
|
|
|
} else {
|
|
|
|
emit signalCollectionImagesLoaded(m_coll);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_cancelImageWriting = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::writeAllImages(int cacheDir_, const KURL& localDir_) {
|
|
|
|
// images get 80 steps in saveDocument()
|
|
|
|
const uint stepSize = 1 + TQMAX(1, m_coll->entryCount()/80); // add 1 since it could round off
|
|
|
|
uint j = 1;
|
|
|
|
|
|
|
|
TQString oldLocalDir = ImageFactory::localDir();
|
|
|
|
ImageFactory::setLocalDirectory(localDir_);
|
|
|
|
|
|
|
|
ImageFactory::CacheDir cacheDir = static_cast<ImageFactory::CacheDir>(cacheDir_);
|
|
|
|
|
|
|
|
TQString id;
|
|
|
|
StringSet images;
|
|
|
|
EntryVec entries = m_coll->entries();
|
|
|
|
FieldVec imageFields = m_coll->imageFields();
|
|
|
|
for(EntryVec::Iterator entry = entries.begin(); entry != entries.end(); ++entry) {
|
|
|
|
for(FieldVec::Iterator field = imageFields.begin(); field != imageFields.end() && !m_cancelImageWriting; ++field) {
|
|
|
|
id = entry->field(field);
|
|
|
|
if(id.isEmpty() || images.has(id)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
images.add(id);
|
|
|
|
if(ImageFactory::imageInfo(id).linkOnly) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(!ImageFactory::writeCachedImage(id, cacheDir)) {
|
|
|
|
myDebug() << "Document::writeAllImages() - did not write image for entry title: " << entry->title() << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(j%stepSize == 0) {
|
|
|
|
ProgressManager::self()->setProgress(this, j/stepSize);
|
|
|
|
kapp->processEvents();
|
|
|
|
}
|
|
|
|
++j;
|
|
|
|
if(m_cancelImageWriting) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_cancelImageWriting) {
|
|
|
|
myDebug() << "Document::writeAllImages() - cancel image writing" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_cancelImageWriting = false;
|
|
|
|
ImageFactory::setLocalDirectory(oldLocalDir);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Document::pruneImages() {
|
|
|
|
bool found = false;
|
|
|
|
TQString id;
|
|
|
|
StringSet images;
|
|
|
|
Data::EntryVec entries = m_coll->entries();
|
|
|
|
Data::FieldVec imageFields = m_coll->imageFields();
|
|
|
|
for(Data::EntryVec::Iterator entry = entries.begin(); entry != entries.end(); ++entry) {
|
|
|
|
for(Data::FieldVec::Iterator field = imageFields.begin(); field != imageFields.end(); ++field) {
|
|
|
|
id = entry->field(field);
|
|
|
|
if(id.isEmpty() || images.has(id)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const Data::Image& img = ImageFactory::imageById(id);
|
|
|
|
if(img.isNull()) {
|
|
|
|
entry->setField(field, TQString());
|
|
|
|
found = true;
|
|
|
|
myDebug() << "Document::pruneImages() - removing null image for " << entry->title() << ": " << id << endl;
|
|
|
|
} else {
|
|
|
|
images.add(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Document::imageCount() const {
|
|
|
|
if(!m_coll) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
StringSet images;
|
|
|
|
FieldVec fields = m_coll->imageFields();
|
|
|
|
EntryVec entries = m_coll->entries();
|
|
|
|
for(FieldVecIt f = fields.begin(); f != fields.end(); ++f) {
|
|
|
|
for(EntryVecIt e = entries.begin(); e != entries.end(); ++e) {
|
|
|
|
images.add(e->field(f->name()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return images.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
Tellico::Data::EntryVec Document::sortEntries(EntryVec entries_) const {
|
|
|
|
std::vector<EntryPtr> vec;
|
|
|
|
for(EntryVecIt e = entries_.begin(); e != entries_.end(); ++e) {
|
|
|
|
vec.push_back(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList titles = Controller::self()->sortTitles();
|
|
|
|
// have to go in reverse for sorting
|
|
|
|
for(int i = titles.count()-1; i >= 0; --i) {
|
|
|
|
if(titles[i].isEmpty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
TQString field = m_coll->fieldNameByTitle(titles[i]);
|
|
|
|
std::sort(vec.begin(), vec.end(), EntryCmp(field));
|
|
|
|
}
|
|
|
|
|
|
|
|
Data::EntryVec sorted;
|
|
|
|
for(std::vector<EntryPtr>::iterator it = vec.begin(); it != vec.end(); ++it) {
|
|
|
|
sorted.append(*it);
|
|
|
|
}
|
|
|
|
return sorted;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Document::removeImagesNotInCollection(EntryVec entries_, EntryVec entriesToKeep_) {
|
|
|
|
// first get list of all images in collection
|
|
|
|
StringSet images;
|
|
|
|
FieldVec fields = m_coll->imageFields();
|
|
|
|
EntryVec allEntries = m_coll->entries();
|
|
|
|
for(FieldVecIt f = fields.begin(); f != fields.end(); ++f) {
|
|
|
|
for(EntryVecIt e = allEntries.begin(); e != allEntries.end(); ++e) {
|
|
|
|
images.add(e->field(f->name()));
|
|
|
|
}
|
|
|
|
for(EntryVecIt e = entriesToKeep_.begin(); e != entriesToKeep_.end(); ++e) {
|
|
|
|
images.add(e->field(f->name()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now for all images not in the cache, we can clear them
|
|
|
|
StringSet imagesToCheck = ImageFactory::imagesNotInCache();
|
|
|
|
|
|
|
|
// if entries_ is not empty, that means we want to limit the images removed
|
|
|
|
// to those that are referenced in those entries
|
|
|
|
StringSet imagesToRemove;
|
|
|
|
for(FieldVecIt f = fields.begin(); f != fields.end(); ++f) {
|
|
|
|
for(EntryVecIt e = entries_.begin(); e != entries_.end(); ++e) {
|
|
|
|
TQString id = e->field(f->name());
|
|
|
|
if(!id.isEmpty() && imagesToCheck.has(id) && !images.has(id)) {
|
|
|
|
imagesToRemove.add(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQStringList realImagesToRemove = imagesToRemove.toList();
|
|
|
|
for(TQStringList::ConstIterator it = realImagesToRemove.begin(); it != realImagesToRemove.end(); ++it) {
|
|
|
|
ImageFactory::removeImage(*it, false); // doesn't delete, just remove link
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "document.moc"
|