//============================================== // copyright : (C) 2003-2005 by Will Stokes //============================================== // This program is free software; you can redistribute it // and/or modify it under the terms of the GNU General // Public License as published by the Free Software // Foundation; either version 2 of the License, or // (at your option) any later version. //============================================== //Systemwide includes #include #include #include #include #include #include #include #include #include //Projectwide includes #include "album.h" #include "subalbum.h" #include "photo.h" #include "tools/imageTools.h" #include "tools/xmlTools.h" #include "tools/md5.h" #include "../config.h" #include "../gui/photoPreviewWidget.h" #include "../gui/statusWidget.h" #include "../gui/subalbumPreviewWidget.h" //============================================== Subalbum::Subalbum(Album* albm, int number) { //set subalbum number this->number = number; //by default no photos in subalbum numPhotos = 0; loadedPhotos = 0; //set strings to default values name = qApp->translate("Subalbum", "Collection %1").arg(number); description =""; //set default rep images smallRepresentativeImage = NULL; mediumRepresentativeImage = SubalbumPreviewWidget::createSubalbumPixmap ( QString(IMAGE_PATH)+"miscImages/subalbum.png" ); largeRepresentativeImage = NULL; //no photos by default firstPhoto = NULL; lastPhoto = NULL; //next and prev pointers null by default prevSubalbum = NULL; nextSubalbum = NULL; //set album pointer this->albm = albm; } //============================================== Subalbum::~Subalbum() { //delete representative images delete smallRepresentativeImage; delete mediumRepresentativeImage; delete largeRepresentativeImage; //delete all photos Photo* current = firstPhoto; while(current != NULL) { Photo* temp = current->getNext(); delete current; current = temp; } } //============================================== QString Subalbum::getName() { return QString(name); } QString Subalbum::getDescription() { return QString(description); } //============================================== QPixmap* Subalbum::getRepresentativeImage(int size) { if(size == SMALL) return smallRepresentativeImage; if(size == MEDIUM) return mediumRepresentativeImage; if(size == LARGE) return largeRepresentativeImage; else return NULL; } //============================================== Album* Subalbum::getAlbum() { return albm; } Subalbum* Subalbum::getPrev() { return prevSubalbum; } Subalbum* Subalbum::getNext() { return nextSubalbum; } Photo* Subalbum::getFirst() { return firstPhoto; } Photo* Subalbum::getLast() { return lastPhoto; } int Subalbum::getSubalbumNumber() { return number; } int Subalbum::getNumPhotos() { return numPhotos; } int Subalbum::getNumLoadedPhotos() { return loadedPhotos; } //============================================== void Subalbum::setName(QString val) { if(name != val) { name = val; albm->setModified(); } } //============================================== void Subalbum::setDescription(QString val) { if(description != val) { description = val; albm->setModified(); } } //============================================== void Subalbum::setRepresentativeImage(QString imageFilename) { //delete old representative images delete smallRepresentativeImage; delete mediumRepresentativeImage; delete largeRepresentativeImage; //if being set to null, set back to defaults if(imageFilename.isNull()) { smallRepresentativeImage = NULL; largeRepresentativeImage = NULL; mediumRepresentativeImage = SubalbumPreviewWidget::createSubalbumPixmap ( QString(IMAGE_PATH)+"miscImages/subalbum.png" ); } //else create various sized cover images else { int imageWidth, imageHeight; getImageSize( imageFilename, imageWidth, imageHeight ); //small version (show at top) int smallRepWidth = 0; int smallRepHeight = 0; calcScaledImageDimensions( imageWidth, imageHeight, 107, REP_IMAGE_HEIGHT, smallRepWidth, smallRepHeight); QImage thumbnailSmall; scaleImage( imageFilename, thumbnailSmall, smallRepWidth, smallRepHeight ); smallRepresentativeImage = new QPixmap( thumbnailSmall.width(), thumbnailSmall.height() ); smallRepresentativeImage->convertFromImage( thumbnailSmall ); //medium version (seen in collections listing) mediumRepresentativeImage = SubalbumPreviewWidget::createSubalbumPixmap( imageFilename ); //large version, used for actually saving out largeRepresentativeImage = new QPixmap( imageFilename ); //--------------------------------------------------------- } //set modified albm->setModified(); } //============================================== void Subalbum::setSubalbumNumber(int newVal) { number = newVal; } void Subalbum::resetNumLoadedPhotos() { loadedPhotos = numPhotos; } void Subalbum::setModified() { albm->setModified(); } //============================================== void Subalbum::addPhoto(Photo* newPhoto) { //set the photos next and prev points to NULL by default newPhoto->setNext(NULL); newPhoto->setPrev(NULL); //if list empty set to head if(firstPhoto == NULL) { firstPhoto = newPhoto; lastPhoto = newPhoto; } //else append to end of list else { lastPhoto->setNext(newPhoto); newPhoto->setPrev( lastPhoto ); lastPhoto = newPhoto; } numPhotos++; albm->setModified(); } //============================================== bool Subalbum::addPhoto(QString fileName, bool replaceDescription, Photo* newPhoto) { //create new photo if necessary if(newPhoto == NULL) newPhoto = new Photo(this, getLast(), numPhotos); //replace description with filename if instructed //(aka /home/bob/happy.jpg -> happy) if(replaceDescription) { //get filename QString desc(fileName); //remove path desc = desc.section( QRegExp("/"), -1); //remove extension if it exists int extensionIndex = desc.findRev( '.' ); if(extensionIndex > 0 ) desc.truncate(extensionIndex); //convert _'s to spaces desc = desc.replace('_', ' '); //set photos description newPhoto->setDescription( desc ); } //attempt to set image if(!newPhoto->setImage(fileName, albm->getNextUniquePhotoID() )) { delete newPhoto; return false; } //if this is the first photo set as the head if(firstPhoto == NULL) { firstPhoto = newPhoto; lastPhoto = newPhoto; } //else append to end of list else { lastPhoto->setNext(newPhoto); newPhoto->setPrev( lastPhoto ); lastPhoto = newPhoto; } numPhotos++; albm->setModified(); return true; } //============================================== bool Subalbum::lazyAddPhoto(QString imageName, QString slideshowName, QString thumbnailName, Photo* newPhoto) { //attempt to set image if(!newPhoto->setImage(imageName, slideshowName, thumbnailName)) { delete newPhoto; return false; } //if this is the first photo set as the head if(firstPhoto == NULL) { firstPhoto = newPhoto; lastPhoto = newPhoto; } //else append to end of list else { lastPhoto->setNext(newPhoto); newPhoto->setPrev( lastPhoto ); lastPhoto = newPhoto; } numPhotos++; albm->setModified(); return true; } //============================================== void Subalbum::removePhoto(Photo* val) { //if photo pointer is null then bail if(val == NULL) return; //reset head and tail pointers if necessary if( val == firstPhoto ) firstPhoto = val->getNext(); if( val == lastPhoto ) lastPhoto = val->getPrev(); //splice out if( val->getPrev() != NULL ) val->getPrev()->setNext( val->getNext() ); if( val->getNext() != NULL ) val->getNext()->setPrev( val->getPrev() ); //delete object delete val; val = NULL; numPhotos--; albm->setModified(); } //============================================== void Subalbum::setPrev(Subalbum* val) { prevSubalbum = val; albm->setModified(); } //============================================== void Subalbum::setNext(Subalbum* val) { nextSubalbum = val; albm->setModified(); } //============================================== void Subalbum::exportToXML(StatusWidget*, QTextStream& stream) { //write subalbum information stream << " \n"; //if subalbum has a represenatative image save it's path if(getRepresentativeImage(LARGE) != NULL ) { stream << " \n"; stream << " " << fixXMLString(name) << "\n"; } //else if the name is empty or just whitespace override it with "Subalbum #" so //it is not invisible on the coverpage else { QString strippedName = fixXMLString(name); if(strippedName.stripWhiteSpace() == "") stream << QString(" %1 %2\n").arg(qApp->translate("Subalbum", "Collection")).arg(number); else stream << " " << fixXMLString(name) << "\n"; } stream << " " << fixXMLString(description) << "\n"; //write photos Photo* current = firstPhoto; while(current != NULL) { current->exportToXML(stream); current = current->getNext(); } //close subalbum stream << " \n"; } //============================================== void Subalbum::importFromDisk(QDomNode* root, int subalbumNum, StatusWidget* status, QString dirName, bool disableCheckPhotoMods) { //if representative image exists load QString repName = QString(dirName + "/img/%1_thumb.jpg").arg(subalbumNum); QImage repImage(repName); if(!repImage.isNull()) { setRepresentativeImage(repName); } QDomNode node = root->firstChild(); QDomText val; int photoNum = 0; while( !node.isNull() ) { //------------------------------------------------------------ //subalbum name if( node.isElement() && node.nodeName() == "name" ) { val = node.firstChild().toText(); if(!val.isNull()) name = val.nodeValue(); name.replace("\\"","\""); } //------------------------------------------------------------ //subalbum description else if( node.isElement() && node.nodeName() == "description" ) { val = node.firstChild().toText(); if(!val.isNull()) description = val.nodeValue(); description.replace("\\"","\""); } //------------------------------------------------------------ //photo else if( node.isElement() && node.nodeName() == "photo" ) { //increase counter photoNum++; //create new photo object QString imageName = QString(dirName + "img/%1/%2.jpg").arg(subalbumNum).arg(photoNum); QString slideshowName = QString(dirName + "img/%1/%2_slideshow.jpg").arg(subalbumNum).arg(photoNum); QString thumbName = QString(dirName + "img/%1/%2_thumb.jpg").arg(subalbumNum).arg(photoNum); Photo* newPhoto = new Photo(this, getLast(), photoNum); //load photo information from disk QDateTime* modificationTimes = newPhoto->importFromDisk( &node ); //first check to see if modifications times have changed bool lazyLoad = true; //assume no modifications //skip checking for mods if disable checking is set if(!disableCheckPhotoMods) { QFileInfo info[3]; info[0].setFile( imageName ); info[1].setFile( slideshowName ); info[2].setFile( thumbName ); if( modificationTimes[0] != info[0].lastModified() || modificationTimes[1] != info[1].lastModified() || modificationTimes[2] != info[2].lastModified() ) lazyLoad = false; } //if no changes have occured do lazy load - don't //bother scaling down thumbnail and slideshow images //from original image std::ifstream imageFile ( QFile::encodeName(imageName) ); std::ifstream slideshowFile( QFile::encodeName(slideshowName) ); std::ifstream thumbnailFile( QFile::encodeName(thumbName) ); if( imageFile.is_open() && thumbnailFile.is_open() && slideshowFile.is_open() && ( lazyLoad || ( getMD5(imageFile) == newPhoto->getImageChecksum() && getMD5(slideshowFile) == newPhoto->getSlideshowChecksum() && getMD5(thumbnailFile) == newPhoto->getThumbnailChecksum() ) ) ) { //close ifstreams imageFile.close(); slideshowFile.close(); thumbnailFile.close(); //populate image lazyAddPhoto(imageName, slideshowName, thumbName, newPhoto); } //else reload image and scale it since changes have occured. else { //close ifstreams if open if(imageFile.is_open()) imageFile.close(); if(thumbnailFile.is_open()) thumbnailFile.close(); //populate image addPhoto(imageName, false, newPhoto); } if(imageFile.is_open()) imageFile.close(); if(slideshowFile.is_open()) slideshowFile.close(); if(thumbnailFile.is_open()) thumbnailFile.close(); //update progress bar status->incrementProgress(); qApp->processEvents(); } //------------------------------------------------------------ //advance to next node node = node.nextSibling(); //------------------------------------------------------------ } //------------------------------------------------------------ //set loaded number resetNumLoadedPhotos(); //------------------------------------------------------------ } //============================================== void Subalbum::photoMoved(Photo* val) { //if null pointer bail if(val == NULL) return; //update first and last pointers if necessary if(val == firstPhoto) firstPhoto = val->getNext(); if(val == lastPhoto) lastPhoto = val->getPrev(); //splice out if(val->getPrev() != NULL) val->getPrev()->setNext( val->getNext() ); if(val->getNext() != NULL) val->getNext()->setPrev( val->getPrev() ); numPhotos--; albm->setModified(); } //============================================== void Subalbum::syncPhotoList(PhotoPreviewWidget* item) { //base case, no items if(item == NULL) { firstPhoto = NULL; lastPhoto = NULL; return; } //set first and last pointers firstPhoto = item->getPhoto(); firstPhoto->setNext(NULL); firstPhoto->setPrev(NULL); lastPhoto = firstPhoto; //set all next/prev pointers while(item->nextItem() != NULL) { item->getPhoto()->setNext( ((PhotoPreviewWidget*)item->nextItem())->getPhoto() ); item->getPhoto()->getNext()->setPrev( item->getPhoto() ); item = (PhotoPreviewWidget*)item->nextItem(); lastPhoto = item->getPhoto(); lastPhoto->setNext(NULL); } } //==============================================