Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

subalbum.cpp

Go to the documentation of this file.
00001 //============================================== 00002 // copyright : (C) 2003-2005 by Will Stokes 00003 //============================================== 00004 // This program is free software; you can redistribute it 00005 // and/or modify it under the terms of the GNU General 00006 // Public License as published by the Free Software 00007 // Foundation; either version 2 of the License, or 00008 // (at your option) any later version. 00009 //============================================== 00010 00011 //Systemwide includes 00012 #include <qimage.h> 00013 #include <qpixmap.h> 00014 #include <qstring.h> 00015 #include <qtextstream.h> 00016 #include <qdom.h> 00017 #include <fstream> 00018 #include <qdir.h> 00019 #include <qregexp.h> 00020 #include <qapplication.h> 00021 00022 //Projectwide includes 00023 #include "album.h" 00024 #include "subalbum.h" 00025 #include "photo.h" 00026 #include "tools/imageTools.h" 00027 #include "tools/xmlTools.h" 00028 #include "tools/md5.h" 00029 #include "../config.h" 00030 #include "../gui/photoPreviewWidget.h" 00031 #include "../gui/statusWidget.h" 00032 #include "../gui/subalbumPreviewWidget.h" 00033 00034 //============================================== 00035 Subalbum::Subalbum(Album* albm, int number) 00036 { 00037 //set subalbum number 00038 this->number = number; 00039 00040 //by default no photos in subalbum 00041 numPhotos = 0; 00042 loadedPhotos = 0; 00043 00044 //set strings to default values 00045 name = qApp->translate("Subalbum", "Collection %1").arg(number); 00046 description =""; 00047 00048 //set default rep images 00049 smallRepresentativeImage = NULL; 00050 mediumRepresentativeImage = SubalbumPreviewWidget::createSubalbumPixmap 00051 ( QString(IMAGE_PATH)+"miscImages/subalbum.png" ); 00052 largeRepresentativeImage = NULL; 00053 00054 //no photos by default 00055 firstPhoto = NULL; 00056 lastPhoto = NULL; 00057 00058 //next and prev pointers null by default 00059 prevSubalbum = NULL; 00060 nextSubalbum = NULL; 00061 00062 //set album pointer 00063 this->albm = albm; 00064 } 00065 //============================================== 00066 Subalbum::~Subalbum() 00067 { 00068 //delete representative images 00069 delete smallRepresentativeImage; 00070 delete mediumRepresentativeImage; 00071 delete largeRepresentativeImage; 00072 00073 //delete all photos 00074 Photo* current = firstPhoto; 00075 while(current != NULL) 00076 { 00077 Photo* temp = current->getNext(); 00078 delete current; 00079 current = temp; 00080 } 00081 } 00082 //============================================== 00083 QString Subalbum::getName() { return QString(name); } 00084 QString Subalbum::getDescription() { return QString(description); } 00085 //============================================== 00086 QPixmap* Subalbum::getRepresentativeImage(int size) 00087 { 00088 if(size == SMALL) return smallRepresentativeImage; 00089 if(size == MEDIUM) return mediumRepresentativeImage; 00090 if(size == LARGE) return largeRepresentativeImage; 00091 else return NULL; 00092 } 00093 //============================================== 00094 Album* Subalbum::getAlbum() { return albm; } 00095 00096 Subalbum* Subalbum::getPrev() { return prevSubalbum; } 00097 Subalbum* Subalbum::getNext() { return nextSubalbum; } 00098 00099 Photo* Subalbum::getFirst() { return firstPhoto; } 00100 Photo* Subalbum::getLast() { return lastPhoto; } 00101 00102 int Subalbum::getSubalbumNumber() { return number; } 00103 int Subalbum::getNumPhotos() { return numPhotos; } 00104 int Subalbum::getNumLoadedPhotos() { return loadedPhotos; } 00105 //============================================== 00106 void Subalbum::setName(QString val) 00107 { 00108 if(name != val) 00109 { 00110 name = val; 00111 albm->setModified(); 00112 } 00113 } 00114 //============================================== 00115 void Subalbum::setDescription(QString val) 00116 { 00117 if(description != val) 00118 { 00119 description = val; 00120 albm->setModified(); 00121 } 00122 } 00123 //============================================== 00124 void Subalbum::setRepresentativeImage(QString imageFilename) 00125 { 00126 //delete old representative images 00127 delete smallRepresentativeImage; 00128 delete mediumRepresentativeImage; 00129 delete largeRepresentativeImage; 00130 00131 //if being set to null, set back to defaults 00132 if(imageFilename.isNull()) 00133 { 00134 smallRepresentativeImage = NULL; 00135 largeRepresentativeImage = NULL; 00136 00137 mediumRepresentativeImage = SubalbumPreviewWidget::createSubalbumPixmap 00138 ( QString(IMAGE_PATH)+"miscImages/subalbum.png" ); 00139 } 00140 //else create various sized cover images 00141 else 00142 { 00143 int imageWidth, imageHeight; 00144 getImageSize( imageFilename, imageWidth, imageHeight ); 00145 00146 //small version (show at top) 00147 int smallRepWidth = 0; 00148 int smallRepHeight = 0; 00149 calcScaledImageDimensions( imageWidth, imageHeight, 00150 107, REP_IMAGE_HEIGHT, 00151 smallRepWidth, smallRepHeight); 00152 QImage thumbnailSmall; 00153 scaleImage( imageFilename, thumbnailSmall, smallRepWidth, smallRepHeight ); 00154 smallRepresentativeImage = new QPixmap( thumbnailSmall.width(), thumbnailSmall.height() ); 00155 smallRepresentativeImage->convertFromImage( thumbnailSmall ); 00156 00157 //medium version (seen in collections listing) 00158 mediumRepresentativeImage = SubalbumPreviewWidget::createSubalbumPixmap( imageFilename ); 00159 00160 //large version, used for actually saving out 00161 largeRepresentativeImage = new QPixmap( imageFilename ); 00162 //--------------------------------------------------------- 00163 } 00164 00165 //set modified 00166 albm->setModified(); 00167 } 00168 //============================================== 00169 void Subalbum::setSubalbumNumber(int newVal) { number = newVal; } 00170 void Subalbum::resetNumLoadedPhotos() { loadedPhotos = numPhotos; } 00171 void Subalbum::setModified() { albm->setModified(); } 00172 //============================================== 00173 void Subalbum::addPhoto(Photo* newPhoto) 00174 { 00175 //set the photos next and prev points to NULL by default 00176 newPhoto->setNext(NULL); 00177 newPhoto->setPrev(NULL); 00178 00179 //if list empty set to head 00180 if(firstPhoto == NULL) 00181 { 00182 firstPhoto = newPhoto; 00183 lastPhoto = newPhoto; 00184 } 00185 //else append to end of list 00186 else 00187 { 00188 lastPhoto->setNext(newPhoto); 00189 newPhoto->setPrev( lastPhoto ); 00190 lastPhoto = newPhoto; 00191 } 00192 00193 numPhotos++; 00194 albm->setModified(); 00195 } 00196 //============================================== 00197 bool Subalbum::addPhoto(QString fileName, bool replaceDescription, Photo* newPhoto) 00198 { 00199 //create new photo if necessary 00200 if(newPhoto == NULL) 00201 newPhoto = new Photo(this, getLast(), numPhotos); 00202 00203 //replace description with filename if instructed 00204 //(aka /home/bob/happy.jpg -> happy) 00205 if(replaceDescription) 00206 { 00207 //get filename 00208 QString desc(fileName); 00209 00210 //remove path 00211 desc = desc.section( QRegExp("/"), -1); 00212 00213 //remove extension if it exists 00214 int extensionIndex = desc.findRev( '.' ); 00215 if(extensionIndex > 0 ) 00216 desc.truncate(extensionIndex); 00217 00218 //convert _'s to spaces 00219 desc = desc.replace('_', ' '); 00220 00221 //set photos description 00222 newPhoto->setDescription( desc ); 00223 } 00224 00225 //attempt to set image 00226 if(!newPhoto->setImage(fileName, albm->getNextUniquePhotoID() )) 00227 { 00228 delete newPhoto; 00229 return false; 00230 } 00231 00232 //if this is the first photo set as the head 00233 if(firstPhoto == NULL) 00234 { 00235 firstPhoto = newPhoto; 00236 lastPhoto = newPhoto; 00237 } 00238 //else append to end of list 00239 else 00240 { 00241 lastPhoto->setNext(newPhoto); 00242 newPhoto->setPrev( lastPhoto ); 00243 lastPhoto = newPhoto; 00244 } 00245 00246 numPhotos++; 00247 albm->setModified(); 00248 return true; 00249 } 00250 //============================================== 00251 bool Subalbum::lazyAddPhoto(QString imageName, QString slideshowName, QString thumbnailName, 00252 Photo* newPhoto) 00253 { 00254 //attempt to set image 00255 if(!newPhoto->setImage(imageName, slideshowName, thumbnailName)) 00256 { 00257 delete newPhoto; 00258 return false; 00259 } 00260 00261 //if this is the first photo set as the head 00262 if(firstPhoto == NULL) 00263 { 00264 firstPhoto = newPhoto; 00265 lastPhoto = newPhoto; 00266 } 00267 //else append to end of list 00268 else 00269 { 00270 lastPhoto->setNext(newPhoto); 00271 newPhoto->setPrev( lastPhoto ); 00272 lastPhoto = newPhoto; 00273 } 00274 00275 numPhotos++; 00276 albm->setModified(); 00277 return true; 00278 } 00279 //============================================== 00280 void Subalbum::removePhoto(Photo* val) 00281 { 00282 //if photo pointer is null then bail 00283 if(val == NULL) return; 00284 00285 //reset head and tail pointers if necessary 00286 if( val == firstPhoto ) firstPhoto = val->getNext(); 00287 if( val == lastPhoto ) lastPhoto = val->getPrev(); 00288 00289 //splice out 00290 if( val->getPrev() != NULL ) val->getPrev()->setNext( val->getNext() ); 00291 if( val->getNext() != NULL ) val->getNext()->setPrev( val->getPrev() ); 00292 00293 //delete object 00294 delete val; 00295 val = NULL; 00296 numPhotos--; 00297 albm->setModified(); 00298 } 00299 //============================================== 00300 void Subalbum::setPrev(Subalbum* val) 00301 { 00302 prevSubalbum = val; 00303 albm->setModified(); 00304 } 00305 //============================================== 00306 void Subalbum::setNext(Subalbum* val) 00307 { 00308 nextSubalbum = val; 00309 albm->setModified(); 00310 } 00311 //============================================== 00312 void Subalbum::exportToXML(StatusWidget*, QTextStream& stream) 00313 { 00314 //write subalbum information 00315 stream << " <subalbum>\n"; 00316 00317 //if subalbum has a represenatative image save it's path 00318 if(getRepresentativeImage(LARGE) != NULL ) 00319 { 00320 stream << " <thumb path=\"img/" << number << "_thumb.jpg\"/>\n"; 00321 stream << " <name>" << fixXMLString(name) << "</name>\n"; 00322 } 00323 //else if the name is empty or just whitespace override it with "Subalbum #" so 00324 //it is not invisible on the coverpage 00325 else 00326 { 00327 QString strippedName = fixXMLString(name); 00328 if(strippedName.stripWhiteSpace() == "") 00329 stream << QString(" <name>%1 %2</name>\n").arg(qApp->translate("Subalbum", "Collection")).arg(number); 00330 else 00331 stream << " <name>" << fixXMLString(name) << "</name>\n"; 00332 } 00333 00334 stream << " <description>" << fixXMLString(description) << "</description>\n"; 00335 00336 //write photos 00337 Photo* current = firstPhoto; 00338 while(current != NULL) 00339 { 00340 current->exportToXML(stream); 00341 current = current->getNext(); 00342 } 00343 00344 //close subalbum 00345 stream << " </subalbum>\n"; 00346 00347 } 00348 //============================================== 00349 void Subalbum::importFromDisk(QDomNode* root, 00350 int subalbumNum, 00351 StatusWidget* status, 00352 QString dirName, 00353 bool disableCheckPhotoMods) 00354 { 00355 //if representative image exists load 00356 QString repName = QString(dirName + "/img/%1_thumb.jpg").arg(subalbumNum); 00357 QImage repImage(repName); 00358 if(!repImage.isNull()) 00359 { 00360 setRepresentativeImage(repName); 00361 } 00362 00363 QDomNode node = root->firstChild(); 00364 QDomText val; 00365 int photoNum = 0; 00366 while( !node.isNull() ) 00367 { 00368 //------------------------------------------------------------ 00369 //subalbum name 00370 if( node.isElement() && node.nodeName() == "name" ) 00371 { 00372 val = node.firstChild().toText(); 00373 if(!val.isNull()) 00374 name = val.nodeValue(); 00375 name.replace("\\&quot;","\""); 00376 } 00377 //------------------------------------------------------------ 00378 //subalbum description 00379 else if( node.isElement() && node.nodeName() == "description" ) 00380 { 00381 val = node.firstChild().toText(); 00382 if(!val.isNull()) 00383 description = val.nodeValue(); 00384 description.replace("\\&quot;","\""); 00385 } 00386 //------------------------------------------------------------ 00387 //photo 00388 else if( node.isElement() && node.nodeName() == "photo" ) 00389 { 00390 //increase counter 00391 photoNum++; 00392 00393 //create new photo object 00394 QString imageName = QString(dirName + "img/%1/%2.jpg").arg(subalbumNum).arg(photoNum); 00395 QString slideshowName = QString(dirName + "img/%1/%2_slideshow.jpg").arg(subalbumNum).arg(photoNum); 00396 QString thumbName = QString(dirName + "img/%1/%2_thumb.jpg").arg(subalbumNum).arg(photoNum); 00397 Photo* newPhoto = new Photo(this, getLast(), photoNum); 00398 00399 //load photo information from disk 00400 QDateTime* modificationTimes = newPhoto->importFromDisk( &node ); 00401 00402 //first check to see if modifications times have changed 00403 bool lazyLoad = true; //assume no modifications 00404 00405 //skip checking for mods if disable checking is set 00406 if(!disableCheckPhotoMods) 00407 { 00408 QFileInfo info[3]; 00409 info[0].setFile( imageName ); 00410 info[1].setFile( slideshowName ); 00411 info[2].setFile( thumbName ); 00412 if( 00413 modificationTimes[0] != info[0].lastModified() || 00414 modificationTimes[1] != info[1].lastModified() || 00415 modificationTimes[2] != info[2].lastModified() 00416 ) 00417 lazyLoad = false; 00418 } 00419 00420 //if no changes have occured do lazy load - don't 00421 //bother scaling down thumbnail and slideshow images 00422 //from original image 00423 std::ifstream imageFile ( QFile::encodeName(imageName) ); 00424 std::ifstream slideshowFile( QFile::encodeName(slideshowName) ); 00425 std::ifstream thumbnailFile( QFile::encodeName(thumbName) ); 00426 00427 if( imageFile.is_open() && 00428 thumbnailFile.is_open() && 00429 slideshowFile.is_open() && 00430 ( 00431 lazyLoad || 00432 ( 00433 getMD5(imageFile) == newPhoto->getImageChecksum() && 00434 getMD5(slideshowFile) == newPhoto->getSlideshowChecksum() && 00435 getMD5(thumbnailFile) == newPhoto->getThumbnailChecksum() 00436 ) 00437 ) 00438 ) 00439 { 00440 //close ifstreams 00441 imageFile.close(); 00442 slideshowFile.close(); 00443 thumbnailFile.close(); 00444 00445 //populate image 00446 lazyAddPhoto(imageName, slideshowName, thumbName, newPhoto); 00447 } 00448 //else reload image and scale it since changes have occured. 00449 else 00450 { 00451 //close ifstreams if open 00452 if(imageFile.is_open()) 00453 imageFile.close(); 00454 if(thumbnailFile.is_open()) 00455 thumbnailFile.close(); 00456 00457 //populate image 00458 addPhoto(imageName, false, newPhoto); 00459 } 00460 00461 if(imageFile.is_open()) 00462 imageFile.close(); 00463 if(slideshowFile.is_open()) 00464 slideshowFile.close(); 00465 if(thumbnailFile.is_open()) 00466 thumbnailFile.close(); 00467 00468 //update progress bar 00469 status->incrementProgress(); 00470 qApp->processEvents(); 00471 } 00472 //------------------------------------------------------------ 00473 //advance to next node 00474 node = node.nextSibling(); 00475 //------------------------------------------------------------ 00476 } 00477 //------------------------------------------------------------ 00478 //set loaded number 00479 resetNumLoadedPhotos(); 00480 //------------------------------------------------------------ 00481 } 00482 //============================================== 00483 void Subalbum::photoMoved(Photo* val) 00484 { 00485 //if null pointer bail 00486 if(val == NULL) return; 00487 00488 //update first and last pointers if necessary 00489 if(val == firstPhoto) firstPhoto = val->getNext(); 00490 if(val == lastPhoto) lastPhoto = val->getPrev(); 00491 00492 //splice out 00493 if(val->getPrev() != NULL) val->getPrev()->setNext( val->getNext() ); 00494 if(val->getNext() != NULL) val->getNext()->setPrev( val->getPrev() ); 00495 00496 numPhotos--; 00497 albm->setModified(); 00498 } 00499 //============================================== 00500 void Subalbum::syncPhotoList(PhotoPreviewWidget* item) 00501 { 00502 //base case, no items 00503 if(item == NULL) 00504 { 00505 firstPhoto = NULL; 00506 lastPhoto = NULL; 00507 return; 00508 } 00509 00510 //set first and last pointers 00511 firstPhoto = item->getPhoto(); 00512 firstPhoto->setNext(NULL); 00513 firstPhoto->setPrev(NULL); 00514 lastPhoto = firstPhoto; 00515 00516 //set all next/prev pointers 00517 while(item->nextItem() != NULL) 00518 { 00519 item->getPhoto()->setNext( ((PhotoPreviewWidget*)item->nextItem())->getPhoto() ); 00520 item->getPhoto()->getNext()->setPrev( item->getPhoto() ); 00521 item = (PhotoPreviewWidget*)item->nextItem(); 00522 lastPhoto = item->getPhoto(); 00523 lastPhoto->setNext(NULL); 00524 } 00525 00526 } 00527 //==============================================

Generated on Sun Mar 4 19:42:57 2007 for AlbumShaper by doxygen 1.3.7