//============================================== // 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 //Projectwide includes #include "window.h" #include "titleWidget.h" #include "layoutWidget.h" #include "subalbumWidget.h" #include "subalbumsWidget.h" #include "photoPreviewWidget.h" #include "photosIconView.h" #include "statusWidget.h" #include "dialogs/addPhotosDialog.h" #include "dialogs/questionDialog.h" #include "dialogs/alertDialog.h" #include "../config.h" #include "../backend/subalbum.h" #include "../backend/photo.h" #include "../backend/tools/guiTools.h" #include "../backend/tools/wallpaperTools.h" #include "../configuration/configuration.h" #include "../backend/album.h" //============================================== SubalbumWidget::SubalbumWidget(Subalbum* salbum, QWidget *parent, const char* name ) : QWidget(parent,name) { setWFlags(WNoAutoErase); //store subalbum pointer subalbum = salbum; //store layout pointer layout = (LayoutWidget*)parent; //create photo collection photos = new PhotosIconView( this ); //establish a top-down view such that the scrollbar is always placed on the right photos->setArrangement( QIconView::LeftToRight ); photos->setVScrollBarMode( QScrollView::Auto ); //allow multiple photos to be selected with control and shift keys photos->setSelectionMode( QIconView::Extended ) ; //set auto-scroll on for drag-n-drop photos->setDragAutoScroll(true); photos->setAcceptDrops(true); //connect selectionChanged signal to update buttons method connect( photos, SIGNAL(selectionChanged()), this, SLOT( selectionChangedEvent()) ); //connect rightButtonClicked signal to update buttons method connect( photos, SIGNAL(rightButtonClicked(QIconViewItem*, const QPoint&)), this, SLOT(selectionChangedEvent()) ); //connect itemhasMoved signal on iconview to reorder slot (phots have been rearranged) connect( photos, SIGNAL(itemHasMoved()), SLOT(reorder()) ); //connect addPhtos signal from iconview to actually add photos from disk (Drop from outside target, ie konqueror) connect( photos, SIGNAL(addPhotos(QStringList)), SLOT(addImageAction(QStringList)) ); //connect keyevent signals from iconview connect( photos, SIGNAL(removeSelectedPhotos()), SLOT(removeImageAction()) ); connect( photos, SIGNAL(rotate90SelectedPhotos()), SLOT(rotate90ImageAction()) ); connect( photos, SIGNAL(rotate270SelectedPhotos()), SLOT(rotate270ImageAction()) ); //connect key e press signal to edit slot connect( photos, SIGNAL(editSelectedPhoto()), layout, SLOT(editSelectedPhoto()) ); //connect double click signal to edit slot connect( photos, SIGNAL( doubleClicked(QIconViewItem*) ), layout, SLOT(editSelectedPhoto()) ); //create all buttons buttonsFrame = new QFrame(this); if(subalbum == NULL) buttonsFrame->hide(); QFont buttonFont( qApp->font() ); buttonFont.setBold(true); buttonFont.setPointSize( 11 ); addImage = new QToolButton( buttonsFrame ); addImage->setTextLabel(tr("Add Photo")); addImage->setIconSet( QPixmap(QString(IMAGE_PATH)+"buttonIcons/add.png") ); addImage->setTextPosition(QToolButton::Right); addImage->setFont( buttonFont ); addImage->setUsesTextLabel( true ); addImage->setEnabled( true ); QToolTip::add( addImage, tr("Add photos to selected collection") ); connect( addImage, SIGNAL(clicked()), SLOT(addImageAction()) ); removeImage = new QToolButton( buttonsFrame ); removeImage->setTextLabel(tr("Remove Photo")); removeImage->setIconSet( QPixmap(QString(IMAGE_PATH)+"buttonIcons/remove.png") ); removeImage->setTextPosition(QToolButton::Right); removeImage->setFont( buttonFont ); removeImage->setUsesTextLabel( true ); removeImage->setEnabled( true ); QToolTip::add( removeImage, tr("Remove selected photos from collection") ); connect( removeImage, SIGNAL(clicked()), SLOT(removeImageAction()) ); rotate90Image = new QToolButton( buttonsFrame ); rotate90Image->setTextLabel(tr("Rotate Right") ); QIconSet rotate90Icon; rotate90Icon.setPixmap( QString(IMAGE_PATH)+"buttonIcons/rotate90.png", QIconSet::Automatic, QIconSet::Normal ); rotate90Icon.setPixmap( QString(IMAGE_PATH)+"buttonIcons/rotate90_disabled.png", QIconSet::Automatic, QIconSet::Disabled ); rotate90Image->setIconSet( rotate90Icon ); rotate90Image->setTextPosition(QToolButton::Right); rotate90Image->setFont( buttonFont ); rotate90Image->setUsesTextLabel( true ); QToolTip::add( rotate90Image, tr("Rotate selected photos clockwise") ); connect( rotate90Image, SIGNAL(clicked()), SLOT(rotate90ImageAction()) ); rotate270Image = new QToolButton( buttonsFrame ); rotate270Image->setTextLabel(tr("Rotate Left") ); QIconSet rotate270Icon; rotate270Icon.setPixmap( QString(IMAGE_PATH)+"buttonIcons/rotate270.png", QIconSet::Automatic, QIconSet::Normal ); rotate270Icon.setPixmap( QString(IMAGE_PATH)+"buttonIcons/rotate270_disabled.png", QIconSet::Automatic, QIconSet::Disabled ); rotate270Image->setIconSet( rotate270Icon ); rotate270Image->setTextPosition(QToolButton::Right); rotate270Image->setFont( buttonFont ); rotate270Image->setUsesTextLabel( true ); QToolTip::add( rotate270Image, tr("Rotate selected photos counterclockwise") ); connect( rotate270Image, SIGNAL(clicked()), SLOT(rotate270ImageAction()) ); //place all items in grid layout buttonsGrid = new QGridLayout( buttonsFrame, 1, 7, 0 ); buttonsGrid->addWidget( addImage, 0, 1, Qt::AlignLeft ); buttonsGrid->addWidget( removeImage, 0, 2, Qt::AlignLeft ); buttonsGrid->addWidget( rotate90Image, 0, 3, Qt::AlignLeft ); buttonsGrid->addWidget( rotate270Image, 0, 4, Qt::AlignLeft ); buttonsGrid->setColStretch( 0, 1 ); buttonsGrid->setColStretch( 6, 1 ); //If setting the desktop wallpaper is supported on this system then add this button as well if( setWallpaperSupported() ) { setDesktopBtn = new QToolButton( buttonsFrame ); setDesktopBtn->setUsesTextLabel( true ); setDesktopBtn->setTextLabel(tr("Wallpaper") ); QIconSet setDesktopIcon; setDesktopIcon.setPixmap( QString(IMAGE_PATH)+"buttonIcons/setDesktopWallpaper.png", QIconSet::Automatic, QIconSet::Normal ); setDesktopIcon.setPixmap( QString(IMAGE_PATH)+"buttonIcons/setDesktopWallpaper_disabled.png", QIconSet::Automatic, QIconSet::Disabled ); setDesktopBtn->setIconSet( setDesktopIcon ); setDesktopBtn->setTextPosition(QToolButton::Right); setDesktopBtn->setFont( buttonFont ); setDesktopBtn->setUsesTextLabel( true ); QToolTip::add( setDesktopBtn, tr("Set desktop wallpaper to selected photo") ); connect( setDesktopBtn, SIGNAL( clicked() ), this, SLOT( setWallpaperAction() ) ); buttonsGrid->addWidget( setDesktopBtn, 0, 5, Qt::AlignLeft ); } else { setDesktopBtn = NULL; } mainGrid = new QGridLayout( this, 2, 1, 0 ); mainGrid->addMultiCellWidget( photos, 0, 0, 0, 1 ); mainGrid->addMultiCellWidget( buttonsFrame, 1, 1, 0, 1 ); mainGrid->setRowStretch( 0, 1 ); //set the background of the widget to be light blue setPaletteBackgroundColor( QColor(193, 210, 238) ); //by default no selected images so disable all buttons besides add removeImage->setEnabled(false); rotate90Image->setEnabled(false); rotate270Image->setEnabled(false); //hook-up keyboard shortcut for deselecting all photos //iconview provides select all shortcut for us QAccel *keyAccel = new QAccel( this ); keyAccel->connectItem( keyAccel->insertItem( CTRL + SHIFT + Key_A ), this, SLOT(deselectAll()) ); } //============================================== void SubalbumWidget::setSubalbum(Subalbum* salbum) { //set new subalbum pointer subalbum = salbum; //update photo listing refreshPhotos(); if(subalbum == NULL) { buttonsFrame->hide(); } else { //disable/enable buttons as necessary buttonsFrame->show(); selectionChangedEvent(); } } //============================================== void SubalbumWidget::addImageAction() { //--------------- //get file list Configuration* config = ((Window*)qApp->mainWidget())->getConfig(); QString path = config->getString( "loadSave", "addPhotoDir" ); QDir testPath(path); if(!testPath.exists()) { config->resetSetting( "loadSave", "addPhotoDir" ); path = config->getString( "loadSave", "addPhotoDir" ); } AddPhotosDialog* fileDialog = new AddPhotosDialog( path ); bool setDescriptions; QStringList fileNames = fileDialog->getFilenames( setDescriptions ); if(!fileNames.empty()) { //store this addPhoto location QDir lastDir = QDir( QFileInfo(*fileNames.begin()).dirPath() ); config->setString( "loadSave", "addPhotoDir", lastDir.path() ); addImageAction( fileNames, setDescriptions ); } } //============================================== void SubalbumWidget::addImageAction(QStringList fileNames, bool setDescriptions) { if(fileNames.empty()) return; //--------------- //set busy flag and deactivate menu's/buttons, and selecting photos layout->getWindow()->getTitle()->setBusy(true); layout->getSubalbums()->updateButtons(false); updateButtons(false); photos->setSelectionMode( QIconView::NoSelection ) ; qApp->setOverrideCursor( QCursor(Qt::WaitCursor)); //setup progress bar QString statusMessage = tr("Adding %1 photos:"); layout->getWindow()->getStatus()->showProgressBar( statusMessage.arg(fileNames.count()), fileNames.count() ); qApp->processEvents(); //iterate through each file and add to album QStringList::iterator it; int num=0; for(it = fileNames.begin(); it != fileNames.end(); it++ ) { //update status message layout->getWindow()->getStatus()->updateProgress( num, statusMessage.arg(fileNames.count() - num) ); //if item is a file, add photo if(QFileInfo(*it).isFile() && subalbum->addPhoto(*it, setDescriptions)) { PhotoPreviewWidget* p = new PhotoPreviewWidget( photos, subalbum->getLast() ); photos->ensureItemVisible(p); } num++; qApp->processEvents(); } photos->arrangeItemsInGrid(); //remove progress bar layout->getWindow()->getStatus()->setStatus( tr("Adding photos complete.") ); //notifty title widget that the album's photo count has possible changed layout->getWindow()->getTitle()->updateMenus(); //unset busy flag and activate menu's/buttons layout->getWindow()->getTitle()->setBusy(false); layout->getSubalbums()->updateButtons(true); updateButtons(true); photos->setSelectionMode( QIconView::Extended ) ; qApp->restoreOverrideCursor(); } //============================================== void SubalbumWidget::removeImageAction() { //set busy flag and deactivate menu's/buttons layout->getWindow()->getTitle()->setBusy(true); layout->getSubalbums()->updateButtons(false); updateButtons(false); photos->setSelectionMode( QIconView::NoSelection ) ; //if user has chosen to not receive destructive action warnings, or agrees to the action, then //delete photo and refresh view bool proceed = !((Window*)qApp->mainWidget())->getConfig()->getBool( "alerts", "showDestructiveAlerts" ); if(!proceed) { QuestionDialog sure( tr("Remove selected photos?"), tr("Once removed photos cannot be restored. Furthermore upon resaving they are physically removed from your album."), "alertIcons/warning.png", this ); proceed = sure.exec(); } if(proceed) { qApp->setOverrideCursor( QCursor(Qt::WaitCursor)); //iterate through all photos and remove those that are selected QIconViewItem* current = photos->firstItem(); QIconViewItem* temp; while(current != NULL) { //if not selected move on if(!current->isSelected()) { current = current->nextItem(); continue; } //get next pointer temp = current->nextItem(); //grab point to backend photo Photo* phto = ((PhotoPreviewWidget*)current)->getPhoto(); //delete photo widget delete current; current = temp; //delete backend photo subalbum->removePhoto(phto); } //cleanup arrangement in case items were deleted in the middle or front photos->arrangeItemsInGrid(); //unset busy flag and activate menu's/buttons qApp->restoreOverrideCursor(); } layout->getWindow()->getTitle()->setBusy(false); layout->getSubalbums()->updateButtons(true); updateButtons(true); photos->setSelectionMode( QIconView::Extended ) ; //update buttons and emit selection changed signal selectionChangedEvent(); } //============================================== void SubalbumWidget::revertSelectedPhotos() { //iterate over photos in current collection QIconViewItem* current = photos->firstItem(); while(current != NULL) { //found a selected item! if(current->isSelected()) { ((PhotoPreviewWidget*)current)->getPhoto()->revertPhoto(); photos->ensureItemVisible(((PhotoPreviewWidget*)current)); ((PhotoPreviewWidget*)current)->updateImage(); qApp->processEvents(); } //move to next item current = current->nextItem(); } //state of selected photos has changed emit selectedPhotoStateChanged(); } //============================================== void SubalbumWidget::setWallpaperAction() { //get first selected photo, if no photo is selected then bail Photo* phto = getSelectedPhoto(); if(phto == NULL) return; //set the wallpaper setWallpaper( phto ); } //============================================== void SubalbumWidget::rotate90ImageAction() { //set busy flag and deactivate menu's/buttons qApp->setOverrideCursor( QCursor(Qt::WaitCursor)); layout->getWindow()->getTitle()->setBusy(true); layout->getSubalbums()->updateButtons(false); photos->setSelectionMode( QIconView::NoSelection ) ; updateButtons(false); //setup progress bar QString statusMessage = tr("Rotating %1 photos:"); layout->getWindow()->getStatus()->showProgressBar( statusMessage.arg(photos->numSelected()), photos->numSelected() ); qApp->processEvents(); //rotate the selected photos int num = 0; QIconViewItem* current = photos->firstItem(); while(current != NULL) { if(current->isSelected()) { //update status message layout->getWindow()->getStatus()->updateProgress( num, statusMessage.arg(photos->numSelected() - num) ); ((PhotoPreviewWidget*)current)->getPhoto()->rotate90(); photos->ensureItemVisible(((PhotoPreviewWidget*)current)); ((PhotoPreviewWidget*)current)->updateImage(); num++; layout->getWindow()->getStatus()->updateProgress( num ); qApp->processEvents(); } //move to next item current = current->nextItem(); } //state of selected photos has changed emit selectedPhotoStateChanged(); //hide progress bar layout->getWindow()->getStatus()->setStatus( tr("Rotating complete.") ); //not busy any more layout->getWindow()->getTitle()->setBusy(false); layout->getSubalbums()->updateButtons(true); updateButtons(true); photos->setSelectionMode( QIconView::Extended ) ; qApp->restoreOverrideCursor(); } //============================================== void SubalbumWidget::rotate270ImageAction() { //set busy flag and deactivate menu's/buttons qApp->setOverrideCursor( QCursor(Qt::WaitCursor)); layout->getWindow()->getTitle()->setBusy(true); layout->getSubalbums()->updateButtons(false); photos->setSelectionMode( QIconView::NoSelection ) ; updateButtons(false); //setup progress bar QString statusMessage = tr("Rotating %1 photos:"); layout->getWindow()->getStatus()->showProgressBar( statusMessage.arg(photos->numSelected()), photos->numSelected() ); qApp->processEvents(); //rotate the selected photos int num = 0; QIconViewItem* current = photos->firstItem(); while(current != NULL) { if(current->isSelected()) { //update status message layout->getWindow()->getStatus()->updateProgress( num, statusMessage.arg(photos->numSelected() - num) ); ((PhotoPreviewWidget*)current)->getPhoto()->rotate270(); photos->ensureItemVisible(((PhotoPreviewWidget*)current)); ((PhotoPreviewWidget*)current)->updateImage(); num++; layout->getWindow()->getStatus()->updateProgress( num ); qApp->processEvents(); } //move to next item current = current->nextItem(); } //state of selected photos has changed emit selectedPhotoStateChanged(); //hide progress bar layout->getWindow()->getStatus()->setStatus( tr("Rotating complete.") ); //not busy any more layout->getWindow()->getTitle()->setBusy(false); layout->getSubalbums()->updateButtons(true); updateButtons(true); photos->setSelectionMode( QIconView::Extended ) ; qApp->restoreOverrideCursor(); } //============================================== void SubalbumWidget::refreshPhotos() { //remove all thumbnails photos->clear(); if(subalbum != NULL) { //insert photo thumbnails Photo* currentPhoto = subalbum->getFirst(); while(currentPhoto != NULL) { new PhotoPreviewWidget( photos, currentPhoto ); currentPhoto = currentPhoto->getNext(); } photos->arrangeItemsInGrid(); } } //============================================== void SubalbumWidget::refreshAllPhotos() { QIconViewItem* current = photos->firstItem(); while(current != NULL) { ((PhotoPreviewWidget*)current)->updateImage(); ((PhotoPreviewWidget*)current)->updateDescription(); current = current->nextItem(); } } //============================================== void SubalbumWidget::refreshSelectedPhotos() { QIconViewItem* current = photos->firstItem(); while(current != NULL) { //found a selected item! if(current->isSelected()) { ((PhotoPreviewWidget*)current)->updateImage(); ((PhotoPreviewWidget*)current)->updateDescription(); } //move to next item current = current->nextItem(); } } //============================================== void SubalbumWidget::stripDescriptionsFromSelectedPhotos() { QIconViewItem* current = photos->firstItem(); while(current != NULL) { //found a selected item! if(current->isSelected()) { ((PhotoPreviewWidget*)current)->getPhoto()->setDescription(""); ((PhotoPreviewWidget*)current)->setText( "" ); } //move to next item current = current->nextItem(); } } //============================================== Subalbum* SubalbumWidget::getSubalbum() { return subalbum; } //============================================== Photo* SubalbumWidget::getSelectedPhoto() { //determine if one photo is selected int numSelected = 0; QIconViewItem* current = photos->firstItem(); QIconViewItem* selected = NULL; while(current != NULL) { //found a selected item! if(current->isSelected()) { numSelected++; selected = current; } //if more than one found then bail! if(numSelected > 1) return NULL; //move to next item current = current->nextItem(); } //if one item is selected then return photo pointer if(numSelected == 1) { return ((PhotoPreviewWidget*)selected)->getPhoto(); } else { return NULL; } } //============================================== Photo* SubalbumWidget::getFirstSelectedPhoto() { //determine if one photo is selected QIconViewItem* current = photos->firstItem(); while(current != NULL) { //found a selected item! if(current->isSelected()) { return ((PhotoPreviewWidget*)current)->getPhoto(); } //move to next item current = current->nextItem(); } //no selected items found return NULL; } //============================================== void SubalbumWidget::setSelectedPhoto(Photo* selection) { //select specified photo QIconViewItem* current = photos->firstItem(); while(current != NULL) { if( ((PhotoPreviewWidget*)current)->getPhoto() == selection ) { //deselect all photos->selectAll(false); //select photo and make sure it is visible current->setSelected(true); photos->ensureItemVisible( current ); return; } //move on to next photo current = current->nextItem(); } } //============================================== bool SubalbumWidget::anyPhotosSelected() { QIconViewItem* current = photos->firstItem(); while(current != NULL) { if(current->isSelected()) return true; current = current->nextItem(); } return false; } //============================================== bool SubalbumWidget::anySelectedPhotosRevertable() { QIconViewItem* current = photos->firstItem(); while(current != NULL) { if(current->isSelected()) { if( ((PhotoPreviewWidget*)current)->getPhoto()->revertPossible() ) return true; } current = current->nextItem(); } return false; } //============================================== void SubalbumWidget::resizeEvent( QResizeEvent * ) { photos->arrangeItemsInGrid(); } //============================================== QIconView* SubalbumWidget::getPhotos() { return photos; } //============================================== void SubalbumWidget::reorder() { //so item has been moved, reorder linked list of items as necessary photos->sort( true ); photos->arrangeItemsInGrid(); //sync lists subalbum->syncPhotoList((PhotoPreviewWidget*)photos->firstItem()); } //============================================== void SubalbumWidget::selectionChangedEvent() { //update rotate/add/remove buttons depending on whether or not any items are selected updateButtons(); //emit selection changed signal so other menu's etc an be updated as well emit selectedPhotoStateChanged(); } //============================================== void SubalbumWidget::updateButtons() { int numSelected = 0; QIconViewItem* current = photos->firstItem(); while(current != NULL) { if(current->isSelected()) { numSelected++; //there are effectively 3 states: //1) no items selected -> disable all buttons besides addPhoto //2) one itme selected -> enable all button, including set desktop wallpaper button //3) more than one item selected -> enable all but edit button (since we don't know which photo to edit) //thus once 2 selected photos are found we know we are in the multi select mode and can terminate the search if(numSelected > 1) break; } //move to next item current = current->nextItem(); } if(numSelected == 0) { removeImage->setEnabled(false); rotate90Image->setEnabled(false); rotate270Image->setEnabled(false); if(setDesktopBtn) { setDesktopBtn->setEnabled(false); } layout->setEditTabEnabled(false); } else { removeImage->setEnabled(true); rotate90Image->setEnabled(true); rotate270Image->setEnabled(true); if(setDesktopBtn) { setDesktopBtn->setEnabled(true); } layout->setEditTabEnabled(true); } if(setDesktopBtn) { setDesktopBtn->setEnabled( numSelected == 1 ); } } //============================================== void SubalbumWidget::updateButtons(bool enable) { if(!enable) { buttonsState = rotate90Image->isEnabled(); addImage->setEnabled(enable && true); removeImage->setEnabled(enable && true); rotate90Image->setEnabled(enable); rotate270Image->setEnabled(enable); if(setDesktopBtn) { wallpaperButtonState = setDesktopBtn->isEnabled(); setDesktopBtn->setEnabled(enable); } layout->setEditTabEnabled(enable); } else { addImage->setEnabled(enable && true); removeImage->setEnabled(buttonsState && true); rotate90Image->setEnabled(buttonsState); rotate270Image->setEnabled(buttonsState); if(setDesktopBtn) { setDesktopBtn->setEnabled(wallpaperButtonState); } layout->setEditTabEnabled(buttonsState); } } //============================================== void SubalbumWidget::deselectAll() { photos->selectAll(false); } //==============================================