//============================================== // 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 #include #include #include #include #include //Projectwide includes #include "album.h" #include "subalbum.h" #include "photo.h" #include "tools/imageTools.h" #include "tools/fileTools.h" #include "tools/md5.h" #include "tools/xmlTools.h" #include "../config.h" #include "../gui/subalbumPreviewWidget.h" #include "../gui/statusWidget.h" //============================================== ///Sets default information Album::Album( QString tmpDir, bool createSubalbum ) { //set strings to default values name = ""; description =""; author = ""; theme = "Slick"; this->tmpDir = tmpDir; //by default no representative image smallRepresentativeImage = NULL; largeRepresentativeImage = NULL; //no Subalbums by default firstSubalbum = NULL; lastSubalbum = NULL; //set the creation/modification date to today updateCreationDate(); updateModificationDate(); //no subalbums numSubalbums = 0; numLoadedSubalbums = 0; //not previously saved by default savedToDisk = false; //set default save location (where images are placed before saving) to the tmp directory saveLocation = getTmpDir(); if(createSubalbum) { Subalbum* s = new Subalbum( this, 1 ); appendSubalbum( s ); } //no interesting modifications yet modified = false; nextUniqueID = 0; } //============================================== Album::~Album() { //delete representative image delete smallRepresentativeImage; delete largeRepresentativeImage; //delete subalbums Subalbum* current = firstSubalbum; Subalbum* temp; while(current != NULL) { temp = current->getNext(); delete current; current = temp; } //remove all old tmp dir contents and directory itself if(!tmpDir.isNull()) { QDir oldTmpDir(tmpDir); QString tmpDirName = oldTmpDir.dirName(); QStringList strLst = oldTmpDir.entryList(); QStringList::iterator it; for(it = strLst.begin(); it != strLst.end(); it++) { oldTmpDir.remove(tmpDir + "/" + *it); } oldTmpDir.cdUp(); oldTmpDir.rmdir( tmpDirName ); } } //============================================== int Album::getModificationYear() { return modificationYear; } int Album::getModificationMonth() { return modificationMonth; } int Album::getModificationDay() { return modificationDay; } int Album::getCreationYear() { return creationYear; } int Album::getCreationMonth() { return creationMonth; } int Album::getCreationDay() { return creationDay; } QString Album::getName() { return QString(name); } QString Album::getDescription() { return QString(description); } QString Album::getAuthor() { return QString(author); } //============================================== QPixmap* Album::getRepresentativeImage(int size) { if(size == SMALL) return smallRepresentativeImage; else if(size == LARGE) return largeRepresentativeImage; else return NULL; } //============================================== Subalbum* Album::getFirstSubalbum() { return firstSubalbum; } Subalbum* Album::getLastSubalbum() { return lastSubalbum; } //============================================== bool Album::prevSave() { return savedToDisk; } bool Album::albumModified() { return modified; } //============================================== QString Album::getSaveLocation() { return saveLocation; } QString Album::getTmpDir() { return tmpDir; } QString Album::getTheme() { return theme; } int Album::getNumSubalbums() { return numSubalbums; } //============================================== int Album::getNumPhotos() { //compute number of photos and size on disk int numPhotos = 0; Subalbum* curr = firstSubalbum; while(curr != NULL) { numPhotos+= curr->getNumPhotos(); curr = curr->getNext(); } return numPhotos; } //============================================== void Album::setName(QString val) { if(name != val) { name = val; modified = true; } } //============================================== void Album::setDescription(QString val) { if(description != val) { description = val; modified = true; } } //============================================== void Album::setAuthor(QString val) { if(author != val) { author = val; modified = true; } } //============================================== void Album::setRepresentativeImages(QString imageFilename) { //delete representative images delete smallRepresentativeImage; delete largeRepresentativeImage; //if being set to null, set back to defaults if(imageFilename.isNull()) { smallRepresentativeImage = NULL; largeRepresentativeImage = NULL; } else { //compute representative image sizes int imageWidth, imageHeight; getImageSize( imageFilename, imageWidth, imageHeight ); int smallRepWidth = 0; int smallRepHeight = 0; int largeRepWidth = 0; int largeRepHeight = 0; calcScaledImageDimensions( imageWidth, imageHeight, 107, REP_IMAGE_HEIGHT, smallRepWidth, smallRepHeight); calcScaledImageDimensions( imageWidth, imageHeight, 500, 320, largeRepWidth, largeRepHeight); //create various representative images //copy and scale small version QImage thumbnailSmall; scaleImage( imageFilename, thumbnailSmall, smallRepWidth, smallRepHeight ); smallRepresentativeImage = new QPixmap( thumbnailSmall.width(), thumbnailSmall.height() ); smallRepresentativeImage->convertFromImage( thumbnailSmall ); //copy and scale large version QImage thumbnailLarge; scaleImage( imageFilename, thumbnailLarge, largeRepWidth, largeRepHeight ); largeRepresentativeImage = new QPixmap( thumbnailLarge.width(), thumbnailLarge.height() ); largeRepresentativeImage->convertFromImage( thumbnailLarge ); } //set modified modified = true; } //============================================== void Album::appendSubalbum(Subalbum* val) { //if passed a null pointer bail! if( val == NULL) return; //empty list - stick on front if(firstSubalbum == NULL) { firstSubalbum = val; lastSubalbum = val; } //else - append to end else { lastSubalbum->setNext( val ); val->setPrev( lastSubalbum ); lastSubalbum = val; } numSubalbums++; modified = true; } //============================================== void Album::removeSubalbum(Subalbum* val) { //if passed a null pointer bail! if( val == NULL) return; //reset head and tail pointers if necessary if( val == firstSubalbum ) firstSubalbum = val->getNext(); if( val == lastSubalbum ) lastSubalbum = val->getPrev(); //split 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; numSubalbums--; modified = true; } //============================================== void Album::updateCreationDate() { //set creation date to today QDate date = QDate::currentDate(); creationYear = date.year(); creationMonth = date.month(); creationDay = date.day(); } //============================================== void Album::updateModificationDate() { //set last modification date to today QDate date = QDate::currentDate(); modificationYear = date.year(); modificationMonth = date.month(); modificationDay = date.day(); } //============================================== int Album::importFromDisk(StatusWidget* status, QString fileName, bool disableCheckPhotoMods) { //update file updateXML( QFileInfo(fileName).dirPath(TRUE) ); //open file QFile albumFile( fileName ); //unable to open xml file? alert user if( !albumFile.open( IO_ReadOnly ) ) return ALBUM_READ_ERROR; //parse dom QDomDocument albumDom; if( !albumDom.setContent( &albumFile ) ) return ALBUM_XML_ERROR; //close file albumFile.close(); //get main directory all other files and subdirectories are in QString rootDir = QFileInfo(albumFile).dirPath(TRUE); saveLocation = rootDir + "/img"; //if representative image exists load QImage repImage(rootDir + "/img/album.jpg"); if(!repImage.isNull()) { setRepresentativeImages( rootDir + "/img/album.jpg"); } //count number of photos in album, needed for showing loading progress int numPhotos = 0; QDomElement root = albumDom.documentElement(); QDomNode node = root.firstChild(); while( !node.isNull() ) { if( node.isElement() && node.nodeName() == "subalbum" ) { QDomNode childNode = node.firstChild(); while( !childNode.isNull() ) { if( childNode.isElement() && childNode.nodeName() == "photo" ) numPhotos++; childNode = childNode.nextSibling(); } } node = node.nextSibling(); } //setup progress bar status->showProgressBar( StatusWidget::tr("Loading:"), numPhotos ); qApp->processEvents(); int subalbumNum = 0; //get root node and start parsing DOM root = albumDom.documentElement(); node = root.firstChild(); QDomText val; while( !node.isNull() ) { //------------------------------------------------------------ //album name if( node.isElement() && node.nodeName() == "name" ) { val = node.firstChild().toText(); if(!val.isNull()) name = val.nodeValue(); name.replace("\\"","\""); } //------------------------------------------------------------ //album description else if( node.isElement() && node.nodeName() == "description" ) { val = node.firstChild().toText(); if(!val.isNull()) description = val.nodeValue(); description.replace("\\"","\""); } //------------------------------------------------------------ //album author else if( node.isElement() && node.nodeName() == "author" ) { val = node.firstChild().toText(); if(!val.isNull()) author = val.nodeValue(); author.replace("\\"","\""); } //------------------------------------------------------------ //album theme else if( node.isElement() && node.nodeName() == "theme" ) { val = node.firstChild().toText(); if(!val.isNull()) theme = val.nodeValue(); theme.replace("\\"","\""); } //------------------------------------------------------------ //album creation date else if( node.isElement() && node.nodeName() == "created" ) { val = node.firstChild().toText(); //split value based on spaces, should be 7 fields QStringList vals = QStringList::split( QRegExp(" "), val.nodeValue() ); int i=0; int intVals[3]; QStringList::Iterator it; for ( it = vals.begin(); it != vals.end(); ++it ) { intVals[i] = QString(*it).toInt(); i++; //only read first 3 entires, year/month/day, don't overwrite //buffer on addition entries if xml messed up if(i > 2) break; } creationYear = intVals[0]; creationMonth = intVals[1]; creationDay = intVals[2]; } //------------------------------------------------------------ //subalbum else if( node.isElement() && node.nodeName() == "subalbum" ) { //increase counter subalbumNum++; //create new subalbum Subalbum* salbum = new Subalbum(this, numSubalbums+1); //populate it salbum->importFromDisk( &node, subalbumNum, status, (rootDir + "/"), disableCheckPhotoMods ); //append it to list of subalbums appendSubalbum(salbum); } //------------------------------------------------------------ //advance to next node node = node.nextSibling(); //------------------------------------------------------------ } //reset number of loaded subalbums numLoadedSubalbums = numSubalbums; //hide progress bar status->setStatus( qApp->translate("Album", "Album loaded.") ); //save load directory name and loaded/saved bit saveLocation = rootDir; savedToDisk = true; return ALBUM_LOADED; } //============================================== int Album::exportToDisk(StatusWidget* status, QString dirName, QString themeName) { //check to see if save location has actually changed, if not don't force save images //this occurs when user blindly selects the same old spot, or is just changing the theme used by default bool forceSave = true; if(saveLocation == dirName) forceSave = false; //backup theme and save location, if save fails revert to previous values oldSaveLocation = saveLocation; QString oldTheme = theme; //attempt to save album saveLocation = dirName; theme = themeName; int result = exportToDisk(status, forceSave); //if album saving failed revert save location and theme if(result != ALBUM_EXPORTED) { saveLocation = oldSaveLocation; theme = oldTheme; } //else update tmp save dir else { //remove all old tmp dir contents and directory itself QDir oldTmpDir(tmpDir); QString tmpDirName = oldTmpDir.dirName(); QStringList strLst = oldTmpDir.entryList(); QStringList::iterator it; for(it = strLst.begin(); it != strLst.end(); it++) { oldTmpDir.remove( tmpDir + "/" + *it); } oldTmpDir.cdUp(); oldTmpDir.rmdir( tmpDirName ); //create and set new temp dir location QDir saveDir( saveLocation ); if(!saveDir.exists( "tmp" )) saveDir.mkdir( "tmp" ); tmpDir = saveLocation + "/tmp"; //reset unique id counter nextUniqueID = 0; } //return result return result; } //============================================== int Album::exportToDisk(StatusWidget* status, bool forceSave) { //------------------------------------------ //create subdirs QDir localDir(saveLocation); //img dirs localDir.mkdir("img"); //subalbum dirs localDir.setPath(saveLocation + "/img"); //make a temporary 0 directory for copying new images, they'll be moved to their final //location during the reordering step localDir.mkdir( "0" ); //iterate over each subalbum and create its image directory Subalbum* current = firstSubalbum; int collectionNum = 0; while(current != NULL) { collectionNum++; QString dirName = QString("%1") .arg( collectionNum ); localDir.mkdir(dirName); current = current->getNext(); } //------------------------------------------ //checks worked, go ahead with export //count number of photos int totalPhotos=0; current = firstSubalbum; while(current != NULL) { totalPhotos+=current->getNumPhotos(); current = current->getNext(); } //setup progress bar status->showProgressBar( StatusWidget::tr("Saving:"), 4*totalPhotos ); qApp->processEvents(); //copy over theme resources exportThemeResources( theme ); //export album cover image, subalbum thumbnails exportTopLevelImages(); //export subalbum images (thumbnail, slideshow, and full versions of all images) exportSubalbumImages(status, forceSave); //remove any _orig images for photos which have been reverted to their original form removeStagnantOrigFiles(status); //apply reordering to all images reorderSubalbumImages(status); //reset subalbum numbers to current ordering current = firstSubalbum; int n=0; while(current !=NULL) { n++; current->setSubalbumNumber(n); current = current->getNext(); } //remove collection 0 directory QDir rootDir(saveLocation + "/img/"); rootDir.rmdir( "0" ); //remove old images that nolonger belong removeStagnantImages(); //remove previous html/htm files localDir.setPath(saveLocation); QStringList list = localDir.entryList( QDir::Files ); QStringList::Iterator file; for ( file = list.begin(); file != list.end(); ++file ) { if( (*file).endsWith(".html") || (*file).endsWith(".htm") ) localDir.remove( saveLocation + "/" + *file ); } //export xml structure of album int result = exportToXML(status, saveLocation); if(result != ALBUM_EXPORTED) { return result; } //export various html pages using selected theme transformXMLtoHTML( saveLocation, theme, false ); //------------------------------------------ //remove files from temp folder QDir tmpDirHandle( getTmpDir() ); QStringList strLst = tmpDirHandle.entryList(); QStringList::iterator it; for(it = strLst.begin(); it != strLst.end(); it++) { tmpDirHandle.remove( getTmpDir() + "/" + *it); } //------------------------------------------ savedToDisk = true; //just saved so no modifications since last save modified = false; //hide progress bar status->setStatus( qApp->translate("Album", "Album saved.") ); //------------------------------------------ return ALBUM_EXPORTED; } //============================================== int Album::exportCompressedWebAlbum(StatusWidget* status, QString exportLocation, QString exportMessage) { //------------------------------------------ //copy all images QDir localDir(exportLocation); localDir.mkdir("img"); localDir.setPath(exportLocation + "/img"); //copy album image if(getRepresentativeImage(LARGE) != NULL) { getRepresentativeImage(LARGE)->save(exportLocation + "/img/album.jpg", "JPEG", 95); } else { localDir.remove(exportLocation + "/img/album.jpg"); } int numPhotos = getNumPhotos(); int photosLeft = numPhotos; int updateInverval = numPhotos / 50; int updateCount = 0; //iterate over each collection Subalbum* curCollection = firstSubalbum; int collectionNum=1; while(curCollection != NULL) { QString collectionDir = QString("%1").arg( collectionNum ); localDir.mkdir( collectionDir ); //copy collection image QString collectionThumbFilename = QString(exportLocation + "/img/%1_thumb.jpg" ).arg(collectionNum); if(curCollection->getRepresentativeImage(LARGE) != NULL ) { curCollection->getRepresentativeImage(LARGE)->save( collectionThumbFilename, "JPEG", 95); } else { localDir.remove( collectionThumbFilename ); } //copy each photo Photo* curPhoto = curCollection->getFirst(); int photoNum = 1; while(curPhoto != NULL) { //update status message status->updateProgress( numPhotos - photosLeft, exportMessage.arg( photosLeft ) ); //make sure events are processed every 2% of the photos that are processes updateCount++; if(updateCount > updateInverval) { updateCount = 0; qApp->processEvents(); } //copy files QString newFilePath = QDir::convertSeparators( exportLocation + "/img/" + collectionDir + "/" + QString("%1").arg(photoNum) ); copyFile( curPhoto->getSlideshowFilename(), newFilePath + "_slideshow.jpg" ); copyFile( curPhoto->getThumbnailFilename(), newFilePath + "_thumb.jpg" ); curPhoto = curPhoto->getNext(); photoNum++; photosLeft--; } curCollection = curCollection->getNext(); collectionNum++; } //------------------------------------------ //copy theme resources QStringList fileList; QStringList::Iterator file; //create HTML and misc resources directories localDir.setPath(exportLocation); localDir.mkdir("resources"); //remove all files in these directories from previous saves with other themes localDir.setPath(exportLocation + "/resources"); fileList = localDir.entryList( QDir::Files ); for ( file = fileList.begin(); file != fileList.end(); ++file ) { localDir.remove( exportLocation + "/resources/" + *file ); } //copy files over from theme's directory localDir.setPath(THEMES_PATH + theme + "/resources"); fileList = localDir.entryList( QDir::Files ); for ( file = fileList.begin(); file != fileList.end(); ++file ) { copyFile( THEMES_PATH + theme + "/resources/" + *file, exportLocation + "/resources/" + *file); } //------------------------------------------ //export xml file exportToXML(status, exportLocation); //------------------------------------------ //remove previous html/htm files localDir.setPath(exportLocation); fileList = localDir.entryList( QDir::Files ); for ( file = fileList.begin(); file != fileList.end(); ++file ) { if( (*file).endsWith(".html") || (*file).endsWith(".htm") ) localDir.remove( exportLocation + "/" + *file ); } //------------------------------------------ //construct html files transformXMLtoHTML( exportLocation, theme, true ); //------------------------------------------ //remove xml file localDir.remove( exportLocation + "/Album.xml" ); //------------------------------------------ return ALBUM_EXPORTED; } //============================================== int Album::exportLargeImages(StatusWidget* status, QString exportPath, QString exportMessage) { //determine number of digits collecion # requires uint collectionDigits = (uint) (1 + log( (double) getNumSubalbums() ) / log( 10.0 ) ); //determine number of digits photo # requires, this //involves walking through the album and finding the collection with the most phots first int mostPhotos = 0; Subalbum* curCollection = getFirstSubalbum(); while(curCollection != NULL ) { mostPhotos = QMAX( mostPhotos, curCollection->getNumPhotos() ); curCollection = curCollection->getNext(); } uint photoDigits = (uint) ( 1 + log( (double) mostPhotos ) / log( 10.0 ) ); //------------ //copy files int numPhotos = getNumPhotos(); int photosLeft = numPhotos; int collectionNum = 1; curCollection = getFirstSubalbum(); int updateInverval = numPhotos / 50; int updateCount = 0; while(curCollection != NULL ) { //construct collection string QString collectionString = QString("%1").arg(collectionNum); while(collectionString.length() < collectionDigits) { collectionString = "0" + collectionString; } //copy all photos in collection int photoNum = 1; Photo* curPhoto = curCollection->getFirst(); while(curPhoto != NULL) { //update status message status->updateProgress( numPhotos - photosLeft, exportMessage.arg( photosLeft ) ); //make sure events are processed every 2% of the photos that are processes updateCount++; if(updateCount > updateInverval) { updateCount = 0; qApp->processEvents(); } //construct photo string QString photoString = QString("%1").arg(photoNum); while(photoString.length() < photoDigits) { photoString = "0" + photoString; } //construct new photo path QString newFilePath = QDir::convertSeparators( exportPath + "/" + collectionString + "_" + photoString + ".jpg" ); //copy file copyFile( curPhoto->getImageFilename(), newFilePath ); //move on to next file photosLeft--; curPhoto = curPhoto->getNext(); photoNum++; } //while photo //move on to next collection curCollection = curCollection->getNext(); collectionNum++; }// while collection //------------ return ALBUM_EXPORTED; } //============================================== int Album::exportToXML(StatusWidget* status, QString exportPath) { //update modification date updateModificationDate(); //create/open xml file QFile file( exportPath + "/Album.xml" ); if(file.open(IO_WriteOnly)) { //----- QTextStream stream; stream.setDevice( &file ); stream.setEncoding( QTextStream::UnicodeUTF8 ); //write album information stream << "\n"; stream << "\n"; stream << " " << fixXMLString(name) << "\n"; stream << " " << fixXMLString(description) << "\n"; stream << " " << fixXMLString(author) << "\n"; stream << " " << creationYear << " " << creationMonth << " " << creationDay << "\n"; stream << " " << modificationYear << " " << modificationMonth << " " << modificationDay << "\n"; stream << " " << theme << "\n"; stream << " " << THUMBNAIL_WIDTH << " " << THUMBNAIL_HEIGHT << "\n"; stream << " " << SLIDESHOW_WIDTH << " " << SLIDESHOW_HEIGHT << "\n"; //if album has a represenatative image save it's path if(getRepresentativeImage(LARGE) != NULL ) { stream << " \n"; } //write subalbums Subalbum* current = firstSubalbum; while(current != NULL) { current->exportToXML(status, stream); current = current->getNext(); } //end album stream << "\n"; file.close(); return ALBUM_EXPORTED; } else { return ALBUM_ERROR_OPEN_FILE; } } //============================================== void Album::exportTopLevelImages() { //if image set export it if(getRepresentativeImage(LARGE) != NULL) { getRepresentativeImage(LARGE)->save(saveLocation + "/img/album.jpg", "JPEG", 95); } //else make sure any previously set images are removed else { QDir rootDir(saveLocation + "/img/"); rootDir.remove(saveLocation + "/img/album.jpg"); } //export subalbum thumbs int n=0; Subalbum* current = firstSubalbum; while(current != NULL) { n++; //if subalbum has representative image export it if(current->getRepresentativeImage(LARGE) != NULL ) { QString fileName = QString(saveLocation + "/img/%1_thumb.jpg" ).arg(n); current->getRepresentativeImage(LARGE)->save(fileName, "JPEG", 95); } //otherwise make sure anyprevious set images are removed else { QDir rootDir(saveLocation + "/img/"); rootDir.remove( saveLocation + QString("/img/%1_thumb.jpg").arg(n) ); } current = current->getNext(); } } //============================================== void Album::exportSubalbumImages(StatusWidget* status, bool forceSave) { //iterate over all subalbums int subalbumNumber=0; Subalbum* currentSubalbum = firstSubalbum; while(currentSubalbum != NULL) { subalbumNumber++; //iterate over all photos in this subalbum int photoNumber=0; Photo* currentPhoto = currentSubalbum->getFirst(); while(currentPhoto != NULL) { photoNumber++; //--------------------------------------- //if the current photo does not need to be saved then move on if( !forceSave && !currentPhoto->getNeedsSavingVal() ) { currentPhoto = currentPhoto->getNext(); status->incrementProgress(); qApp->processEvents(); continue; } //--------------------------------------- //get initial photo # and subalbum #, used for saving int initPhotoNumber = currentPhoto->getInitialPhotoNumber(); int initSubalbumNumber = currentPhoto->getInitialSubalbumNumber(); //--------------------------------------- //export thumbnail image QString oldName = currentPhoto->getThumbnailFilename(); QString newName = QString(saveLocation + "/img/%1/%2_thumb.jpg" ) .arg(initSubalbumNumber).arg(initPhotoNumber); //if file has been modified move from current location to final location if( currentPhoto->getNeedsSavingVal() ) { moveFile( oldName, newName ); } //If file has not been modified we must be doing a save-as and saving has been forced. In this case //COPY file from current location to final location, DON'T delete previous copy!!! else { copyFile(oldName, newName); } //compute and store md5 for slideshow image std::ifstream thumbnailFile( QFile::encodeName(newName) ); if(thumbnailFile.is_open()) { currentPhoto->setThumbnailChecksum( getMD5(thumbnailFile) ); thumbnailFile.close(); } //--------------------------------------- //export slideshow image oldName = currentPhoto->getSlideshowFilename(); newName = QString(saveLocation + "/img/%1/%2_slideshow.jpg" ) .arg(initSubalbumNumber).arg(initPhotoNumber); //if file has been modified move from current location to final location if( currentPhoto->getNeedsSavingVal() ) { moveFile( oldName, newName ); } //If file has not been modified we must be doing a save-as and saving has been forced. In this case //COPY file from current location to final location, DON'T delete previous copy!!! else { copyFile(oldName, newName); } //compute and store md5 for slideshow image std::ifstream slideshowFile( QFile::encodeName(newName) ); if(slideshowFile.is_open()) { currentPhoto->setSlideshowChecksum( getMD5(slideshowFile) ); slideshowFile.close(); } //--------------------------------------- //export full size image oldName = currentPhoto->getImageFilename(); newName = QString(saveLocation + "/img/%1/%2.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); //if file has been modified move from current location to final location if( currentPhoto->getNeedsSavingVal() ) { QString tempOrigName = getTmpDir() + QString("/%1_%2_orig.jpg") .arg(initSubalbumNumber).arg(initPhotoNumber); QString finalOrigName = QString(saveLocation + "/img/%1/%2_orig.jpg" ) .arg(initSubalbumNumber).arg(initPhotoNumber); ///Before we move the file we must be sure to preserve the photos original format. ///if the photo was not recently reverted (if it was then we're saving out ///the original form so no need to backup) and the file has previously been saved and ///an orig file does not exist, we better backup the previously saved version quick QDir tmpDir; if( !currentPhoto->getRecentlyReverted() && tmpDir.exists(newName) && !tmpDir.exists(finalOrigName) ) { moveFile( newName, finalOrigName ); } //if photo previously saved, there is no orig file, but the photo //is modified and we're doing a force save than make sure to copy //over the original as well even though it's not an orig file else if ( currentPhoto->getEverSaved() && currentPhoto->getNeedsSavingVal() && forceSave && saveLocation.compare( oldSaveLocation ) != 0 ) { QString storedOrigLocation = oldSaveLocation + QString("/img/%1/%2_orig.jpg").arg(currentPhoto->getInitialSubalbumNumber()) .arg(currentPhoto->getInitialPhotoNumber()); QString storedLocation = oldSaveLocation + QString("/img/%1/%2.jpg").arg(currentPhoto->getInitialSubalbumNumber()) .arg(currentPhoto->getInitialPhotoNumber()); if( tmpDir.exists(storedOrigLocation) ) copyFile( storedOrigLocation, finalOrigName ); else if( tmpDir.exists(storedLocation) ) copyFile( storedLocation, finalOrigName ); } ///If a photo has never been saved before, make sure to also move over any orig file if ///one exists. The presence of such a file indicates a photo was modified before it ///was ever saved, but the original form has been preseved and should be backed up at this ///time to allow a user to revert to the photos original form in the future. else if( !currentPhoto->getRecentlyReverted() && !tmpDir.exists(newName) && tmpDir.exists(tempOrigName) ) { moveFile( tempOrigName, finalOrigName ); } ///ok, now it's safe to move over currrent version of the photo moveFile( oldName, newName ); } //If file does not need to be saved a force save is taking place. This occurs when a user chooses //save as and copies an entire album to a different location so all files must be copied. Make //sure to copy over the original form of the photo as well if this file exists else { //copy current image copyFile( oldName, newName ); ///---- //if orig file exists copy it too QDir tmpDir; QString tempOrigName = getTmpDir() + QString("/%1_%2_orig.jpg") .arg(initSubalbumNumber).arg(initPhotoNumber); QString curOrigName = currentPhoto->getImageFilename(); curOrigName.truncate( curOrigName.length() - 4 ); curOrigName = curOrigName + "_orig.jpg"; QString finalOrigName = QString(saveLocation + "/img/%1/%2_orig.jpg" ) .arg(initSubalbumNumber).arg(initPhotoNumber); //if the photo was recently reverted ignore the presence of orig files if( !currentPhoto->getRecentlyReverted() ) { //if the photo was never previously saved and an orig file //exists in the tmp directory make sure to copy it over if( !currentPhoto->getEverSaved() && tmpDir.exists( tempOrigName ) ) { copyFile( tempOrigName, finalOrigName ); } //if the photo was previously saved and an orig file exists //in the previous save location make sure to copy it over else if( currentPhoto->getEverSaved() && tmpDir.exists( curOrigName ) ) { copyFile( curOrigName, finalOrigName ); } } ///---- } //--------------------------------------- //compute and store md5 for image std::ifstream imageFile( QFile::encodeName(newName) ); if(imageFile.is_open()) { currentPhoto->setImageChecksum( getMD5(imageFile) ); imageFile.close(); } //--------------------------------------- //set new storage locations of files currentPhoto->setImageFilename ( QString(saveLocation + "/img/%1/%2.jpg").arg(initSubalbumNumber).arg(initPhotoNumber) ); currentPhoto->setSlideshowFilename ( QString(saveLocation + "/img/%1/%2_slideshow.jpg").arg(initSubalbumNumber).arg(initPhotoNumber) ); currentPhoto->setThumbnailFilename ( QString(saveLocation + "/img/%1/%2_thumb.jpg").arg(initSubalbumNumber).arg(initPhotoNumber) ); //--------------------------------------- //set image as not needing saving and as being saved currentPhoto->setNeedsSavingVal(false); currentPhoto->setEverSaved(true); //--------------------------------------- //update progress bar status->incrementProgress(); qApp->processEvents(); //--------------------------------------- //move on to next photo in subalbum currentPhoto = currentPhoto->getNext(); //--------------------------------------- } //--------------------------------------- //move on to next subalbum currentSubalbum = currentSubalbum->getNext(); } } //============================================== void Album::removeStagnantOrigFiles(StatusWidget* status) { QDir tmpDir; //iterate over all collections Subalbum* currentSubalbum = firstSubalbum; while(currentSubalbum != NULL) { //iterate over all photos in this subalbum Photo* currentPhoto = currentSubalbum->getFirst(); while(currentPhoto != NULL) { //if photo recently reverted and orig file is not the current filename remove orig file //the orig and current name will match up if a previously saved (but not modified) photo //is modified, reverted, then saved out again if(currentPhoto->getRecentlyReverted() && currentPhoto->getImageFilename().compare( currentPhoto->originalImageFilename() ) != 0 ) { tmpDir.remove( currentPhoto->originalImageFilename() ); currentPhoto->setRecentlyReverted( false ); } //move on to next photo currentPhoto = currentPhoto->getNext(); status->incrementProgress(); qApp->processEvents(); } //move on to next subalbum currentSubalbum = currentSubalbum->getNext(); } } //============================================== void Album::reorderSubalbumImages(StatusWidget* status) { //-------------------------------------------------------- //-------------------------------------------------------- //first pass over all photos, those whose initial and current numbers don't match up //rename slightly so we don't overwrte them the second time around //-------------------------------------------------------- //-------------------------------------------------------- //iterate over all subalbums QDir tmpDir; int subalbumNumber=0; Subalbum* currentSubalbum = firstSubalbum; while(currentSubalbum != NULL) { subalbumNumber++; //iterate over all photos in this subalbum int photoNumber=0; Photo* currentPhoto = currentSubalbum->getFirst(); while(currentPhoto != NULL) { photoNumber++; int initPhotoNumber = currentPhoto->getInitialPhotoNumber(); int initSubalbumNumber = currentPhoto->getInitialSubalbumNumber(); //if photo has moved rename full image, orig image (if it exists), slideshow image, and thumbnail images if( initPhotoNumber != photoNumber || initSubalbumNumber != subalbumNumber) { QString oldName = QString(saveLocation + "/img/%1/%2.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); QString newName = QString(saveLocation + "/img/%1/%2_moved.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); moveFile( oldName, newName ); //----- oldName = QString(saveLocation + "/img/%1/%2_orig.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); newName = QString(saveLocation + "/img/%1/%2_orig_moved.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); if(tmpDir.exists(oldName) ) { moveFile( oldName, newName ); } //----- oldName = QString(saveLocation + "/img/%1/%2_slideshow.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); newName = QString(saveLocation + "/img/%1/%2_slideshow_moved.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); moveFile( oldName, newName ); //----- oldName = QString(saveLocation + "/img/%1/%2_thumb.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); newName = QString(saveLocation + "/img/%1/%2_thumb_moved.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); moveFile( oldName, newName ); } //move on to next photo currentPhoto = currentPhoto->getNext(); status->incrementProgress(); qApp->processEvents(); } //move on to next subalbum currentSubalbum = currentSubalbum->getNext(); } //-------------------------------------------------------- //-------------------------------------------------------- //second pass over all photos, those whose initial and current numbers don't match up //rename to their final names and reset initial photo and subalbum numbers //-------------------------------------------------------- //-------------------------------------------------------- //iterate over all subalbums subalbumNumber=0; currentSubalbum = firstSubalbum; while(currentSubalbum != NULL) { subalbumNumber++; //iterate over all photos in this subalbum int photoNumber=0; Photo* currentPhoto = currentSubalbum->getFirst(); while(currentPhoto != NULL) { photoNumber++; int initPhotoNumber = currentPhoto->getInitialPhotoNumber(); int initSubalbumNumber = currentPhoto->getInitialSubalbumNumber(); //if the current photo has moved rename full image, slideshow image, and thumbnail image to their final names if( initPhotoNumber != photoNumber || initSubalbumNumber != subalbumNumber) { QString oldName = QString(saveLocation + "/img/%1/%2_moved.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); QString newName = QString(saveLocation + "/img/%1/%2.jpg" ).arg(subalbumNumber).arg(photoNumber); moveFile( oldName, newName ); //----- oldName = QString(saveLocation + "/img/%1/%2_orig_moved.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); newName = QString(saveLocation + "/img/%1/%2_orig.jpg" ).arg(subalbumNumber).arg(photoNumber); if(tmpDir.exists(oldName) ) { moveFile( oldName, newName ); } //----- oldName = QString(saveLocation + "/img/%1/%2_slideshow_moved.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); newName = QString(saveLocation + "/img/%1/%2_slideshow.jpg" ).arg(subalbumNumber).arg(photoNumber); moveFile( oldName, newName ); //----- oldName = QString(saveLocation + "/img/%1/%2_thumb_moved.jpg" ).arg(initSubalbumNumber).arg(initPhotoNumber); newName = QString(saveLocation + "/img/%1/%2_thumb.jpg" ).arg(subalbumNumber).arg(photoNumber); moveFile( oldName, newName ); //--------------------------------------- //reset initial photo and subalbum numbers, and filenames currentPhoto->setInitialPhotoNumber(photoNumber); currentPhoto->setInitialSubalbumNumber(subalbumNumber); currentPhoto->setImageFilename( QString(saveLocation + "/img/%1/%2.jpg"). arg(subalbumNumber).arg(photoNumber) ); currentPhoto->setSlideshowFilename( QString(saveLocation + "/img/%1/%2_slideshow.jpg"). arg(subalbumNumber).arg(photoNumber) ); currentPhoto->setThumbnailFilename( QString(saveLocation + "/img/%1/%2_thumb.jpg"). arg(subalbumNumber).arg(photoNumber) ); } //move on to next photo currentPhoto = currentPhoto->getNext(); status->incrementProgress(); qApp->processEvents(); } //move on to next subalbum currentSubalbum = currentSubalbum->getNext(); } } //============================================== void Album::removeStagnantImages() { QDir rootDir(saveLocation + "/img/"); //iterate over each collection int subalbumNumber=0; Subalbum* currentSubalbum = firstSubalbum; while(currentSubalbum != NULL) { subalbumNumber++; //remove all photos who are numbered greater //than the number of photos in the subalbum int photoNum = currentSubalbum->getNumPhotos()+1; while(true) { QString imageString = QString(saveLocation + "/img/%1/%2.jpg").arg(subalbumNumber).arg(photoNum); QString origString = QString(saveLocation + "/img/%1/%2_orig.jpg").arg(subalbumNumber).arg(photoNum); QString slideshowString = QString(saveLocation + "/img/%1/%2_slideshow.jpg").arg(subalbumNumber).arg(photoNum); QString thumbString = QString(saveLocation + "/img/%1/%2_thumb.jpg").arg(subalbumNumber).arg(photoNum); //if none of the possible images exist then assume //no more stagnant images exist in this collection // if( !rootDir.exists(imageString) && !rootDir.exists(origString) && !rootDir.exists(slideshowString) && !rootDir.exists(thumbString) ) break; //else delete photos and move on else { rootDir.remove( imageString ); rootDir.remove( origString ); rootDir.remove( slideshowString ); rootDir.remove( thumbString ); photoNum++; } } //reset number of loaded photos since old photos removed now currentSubalbum->resetNumLoadedPhotos(); //move on to next collection currentSubalbum = currentSubalbum->getNext(); } //--------------------------------- //remove stagnant collections and all their contents subalbumNumber = numSubalbums+1; while(true) { //check to see if the directory exists, if not we are done QString imageDirString = QString(saveLocation + "/img/%1/").arg(subalbumNumber); if( !rootDir.exists(imageDirString) ) break; //get filelist for directory QDir imageDir( imageDirString ); QStringList list = imageDir.entryList( QDir::Files ); //remove each file in directory QStringList::Iterator file; for ( file = list.begin(); file != list.end(); ++file ) { rootDir.remove( QString(saveLocation + "/img/%1/" + *file).arg(subalbumNumber) ); } //remove directory rootDir.rmdir( QString("%1").arg(subalbumNumber) ); //remove thumbnail image rootDir.remove( QString(saveLocation + "/img/%1_thumb.jpg").arg(subalbumNumber) ); //move on to next subalbum subalbumNumber++; } //reset number of loaded subalbums since stagnant directories removed now numLoadedSubalbums = numSubalbums; //--------------------------------- } //============================================== void Album::exportThemeResources( QString theme ) { QStringList fileList; QStringList::Iterator file; QDir localDir; //remove any "resources" directories created by 1.0* versions of Album Shaper localDir.setPath( saveLocation + "/resources" ); fileList = localDir.entryList(); for(file = fileList.begin(); file != fileList.end(); file++) { localDir.remove(saveLocation + "/resources/" + *file); } localDir.cdUp(); localDir.rmdir( "resources" ); //create HTML and misc resources directories localDir.setPath(saveLocation); localDir.mkdir("resources"); // localDir.mkdir("misc_resources"); //remove all files in these directories from previous saves with other themes localDir.setPath(saveLocation + "/resources"); fileList = localDir.entryList( QDir::Files ); for ( file = fileList.begin(); file != fileList.end(); ++file ) { localDir.remove( saveLocation + "/resources/" + *file ); } //-- /* localDir.setPath(saveLocation + "/misc_resources"); fileList = localDir.entryList( QDir::Files ); for ( file = fileList.begin(); file != fileList.end(); ++file ) { localDir.remove( saveLocation + "/misc_resources/" + *file ); } */ //copy files over from theme's directory localDir.setPath(THEMES_PATH + theme + "/resources"); fileList = localDir.entryList( QDir::Files ); for ( file = fileList.begin(); file != fileList.end(); ++file ) { copyFile( THEMES_PATH + theme + "/resources/" + *file, saveLocation + "/resources/" + *file); } //-- /* localDir.setPath(THEMES_PATH + theme + "/misc_resources"); fileList = localDir.entryList( QDir::Files ); for ( file = fileList.begin(); file != fileList.end(); ++file ) { copyFile( THEMES_PATH + theme + "/misc_resources/" + *file, saveLocation + "/misc_resources/" + *file); } */ } //============================================== void Album::syncSubalbumList(SubalbumPreviewWidget* item) { //check to see if any changes actually took place bool change = false; Subalbum* tmp = firstSubalbum; SubalbumPreviewWidget* tmp2 = item; while( tmp2 != NULL) { //pointers do not match up if(tmp != tmp2->getSubalbum() ) { change = true; break; } tmp = tmp->getNext(); tmp2 = (SubalbumPreviewWidget*)tmp2->nextItem(); } //if no change then quit if(!change) return; //base case, no items if(item == NULL) { firstSubalbum = NULL; lastSubalbum = NULL; return; } //set first and last pointers firstSubalbum = item->getSubalbum(); firstSubalbum->setNext(NULL); firstSubalbum->setPrev(NULL); lastSubalbum = firstSubalbum; //set all next pointers while(item->nextItem() != NULL) { item->getSubalbum()->setNext( ((SubalbumPreviewWidget*)item->nextItem())->getSubalbum() ); item->getSubalbum()->getNext()->setPrev( item->getSubalbum() ); item = (SubalbumPreviewWidget*)item->nextItem(); lastSubalbum = item->getSubalbum(); lastSubalbum->setNext(NULL); } } //============================================== void Album::setModified(bool val) { modified = val; } //============================================== int Album::getNextUniquePhotoID() { nextUniqueID++; return nextUniqueID; } //============================================== QStringList Album::getThumbnailFilenames() { //iterate over all collections QStringList thumbnailList; Subalbum* currCollection = firstSubalbum; while(currCollection != NULL) { //iterate over all photos Photo* currPhoto = currCollection->getFirst(); while( currPhoto != NULL ) { thumbnailList.append( currPhoto->getThumbnailFilename() ); currPhoto = currPhoto->getNext(); } currCollection = currCollection->getNext(); } return thumbnailList; } //==============================================